#include "component.h"
#include "device.h"


/* 调试打印接口 */
#define USERS_LOG(format, ...)		OSAL_LOG(C_GREEN format C_NONE, ##__VA_ARGS__)
#define __USERS_LOG(M, ...) 		//__OSAL_LOG(C_GREEN format C_NONE, ##__VA_ARGS__)

/* NV USARS组件初始化标识*/
#define USARS_NV_INIT_FLAG			0xFA

/* 定义默认的指密卡，人脸，指静脉用户的数量 */
#ifndef KOS_PARAM_USERS_QTY_FACE
#define KOS_PARAM_USERS_QTY_FACE   10
#endif

#ifndef KOS_PARAM_USERS_QTY_FINGER
#define KOS_PARAM_USERS_QTY_FINGER 10
#endif

#ifndef KOS_PARAM_USERS_QTY_PWD
#define KOS_PARAM_USERS_QTY_PWD    10
#endif

#ifndef KOS_PARAM_USERS_QTY_CARD
#define KOS_PARAM_USERS_QTY_CARD   10
#endif

#if defined(FINGERVEIN_SUPPORT)
#ifndef KOS_PARAM_USERS_QTY_FINGERVEIN
#define KOS_PARAM_USERS_QTY_FINGERVEIN  0
#endif
#endif

#if defined(PVN_SUPPORT)
#ifndef KOS_PARAM_USERS_QTY_PVN
#define KOS_PARAM_USERS_QTY_PVN   0
#endif
#endif

/* 凭证默认数量20个 */
#if defined(EVIDENCE_SUPPORT)
#ifndef KOS_PARAM_USERS_QTY_EVIDENCE
#define KOS_PARAM_USERS_QTY_EVIDENCE  20
#endif
#endif

#if defined(DXTC_NO_MENU)
#define KEYS_MAX_QTY_PWD			100 //密码最大数量
#define KEYS_MAX_QTY_FPT       	    100 //指纹最大数量
#define KEYS_MAX_QTY_CARD			100 //卡片最大数量
#define KEYS_MAX_QTY_FACE			50 	//人脸数量
#define KEYS_MAX_QTY_FVN			100 //指静脉最大数量
#define KEYS_MAX_QTY_PVN			50  //最大掌静脉数量
#define KEYS_MAX_QTY_EVIDENCE		20  //最大凭证数量
#else
/* 最大密钥数量 */
#if (KOS_PARAM_USERS_QTY_PWD <= 50)
#define KEYS_MAX_QTY_PWD			50  //密码最大数量
#else
#define KEYS_MAX_QTY_PWD			100 //密码最大数量
#endif
#define KEYS_MAX_QTY_FPT       	    100 //指纹最大数量
#define KEYS_MAX_QTY_CARD			100 //卡片最大数量
#if (KOS_PARAM_USERS_QTY_FACE <= 20) //兼容已出货的锁
#define KEYS_MAX_QTY_FACE			20 	//人脸数量
#else
#define KEYS_MAX_QTY_FACE			50 	//人脸数量
#endif
#if defined(FINGERVEIN_SUPPORT)
#define KEYS_MAX_QTY_FVN			100 //指静脉最大数量
#endif
#if defined(PVN_SUPPORT)
#define KEYS_MAX_QTY_PVN			50  //最大掌静脉数量
#endif
#if defined(EVIDENCE_SUPPORT)
#define KEYS_MAX_QTY_EVIDENCE			20  //最大凭证数量
#endif
#endif

#define KEYS_MAP_SIZE_PWD			((KEYS_MAX_QTY_PWD/8)  + 1) //密码位图数组大小7
#define KEYS_MAP_SIZE_FPT			((KEYS_MAX_QTY_FPT/8)  + 1) //指纹位图数组大小13
#define KEYS_MAP_SIZE_CARD			((KEYS_MAX_QTY_CARD/8) + 1) //卡片位图数组大小13
#define KEYS_MAP_SIZE_FACE			((KEYS_MAX_QTY_FACE/8) + 1) //人脸位图数组大小3
#if defined(PVN_SUPPORT)
#define KEYS_MAP_SIZE_PVN           ((KEYS_MAX_QTY_PVN/8) + 1)  //掌静脉位图数组大小7
#endif
#if defined(FINGERVEIN_SUPPORT)
#define KEYS_MAP_SIZE_FVN			((KEYS_MAX_QTY_FVN/8) + 1)  //指静脉位图数组大小13
#endif
#if defined(EVIDENCE_SUPPORT)
#define KEYS_MAP_SIZE_EVIDENCE		((KEYS_MAX_QTY_EVIDENCE/8)  + 1)//凭证位图数组大小3
#endif




//最小密码长度
#ifdef  KOS_PARAM_USERS_PWD_MIN_LEN
#define PWD_LEN_MIN					KOS_PARAM_USERS_PWD_MIN_LEN   
#else
#define PWD_LEN_MIN					6
#endif

//卡片ID最大长度
#define CARD_LEN_MAX				10  

//默认管理员密码
#define DEFAULT_ADMIN_PWD			{1,2,3,4,5,6}

//离线密码相关
#define OFFLINE_PWD_RANDOM_LEN		28   //随机数长度
#define OFFLINE_PWD_LEN				6    //离线密码长度
#if defined(DXTC_NO_MENU)
#define OFFLINE_PWD_QTY				12   //每次计算的离线密码数量
#else
#define OFFLINE_PWD_QTY				8    //每次计算的离线密码数量
#endif

#define KEYS_QTY_PWD				gUsersParam.qty.pwd  //密码数量
#define KEYS_QTY_FPT       			gUsersParam.qty.fpt  //指纹数量
#define KEYS_QTY_CARD      			gUsersParam.qty.card //卡片数量
#define KEYS_QTY_FACE      			gUsersParam.qty.face //人脸数量
#if defined(PVN_SUPPORT)
#define KEYS_QTY_PVN				gUsersParam.qty.pvn  //掌静脉数量
#endif
#if defined(FINGERVEIN_SUPPORT)
#define KEYS_QTY_FVN      			gUsersParam.qty.fvn  //指静脉数量
#endif

#if defined(EVIDENCE_SUPPORT)
#define KEYS_QTY_EVIDENCE      			gUsersParam.qty.evidence  //凭证数量
#endif

#pragma pack(1)


__attribute__((unused)) static ErrorStatus Users_WriteActivationCode(uint8_t *pCode, uint8_t len);
__attribute__((unused)) static ErrorStatus Users_ReadOfflinePwdRandom(uint8_t *random, uint8_t len);
__attribute__((unused)) static ErrorStatus Users_SaveOfflinePwdRandom(uint8_t *random, uint8_t len);
__attribute__((unused)) static ErrorStatus Users_AllKeysIsFull(void);
__attribute__((unused)) static ErrorStatus Users_AllKeysIsEmpty(void);


/* 密码数据（26byte） */
typedef struct
{
	uint8_t  pwd[PWD_LEN_MAX];	//密码

	uint8_t  attr;    			//钥匙属性：永久、一次性、策略……
	uint8_t  week;    			//钥匙策略：周几生效（为0表示当前策略类型为年月日策略）
	uint32_t stime;   			//钥匙策略：起始时间
	uint32_t etime;   			//钥匙策略：结束时间
	uint32_t ctime;   			//钥匙创建时间
}NvPassword_stu_t;

#if defined(DXTC_NO_MENU)
typedef struct
{
	uint32_t timestamp;
	uint8_t index;
}NvInvalidPwd_stu_t;
#endif

/* 离线密码数据（41Byte） */
typedef struct
{
	uint8_t bleSN[13];			/* 蓝牙eSN */
	uint8_t random[OFFLINE_PWD_RANDOM_LEN];
#if defined(DXTC_NO_MENU)
	NvInvalidPwd_stu_t invalid_pwd[2];
#endif
}NvOfflinePwm_stu_t;

/* 指纹数据（15byte） */
typedef struct
{
	uint8_t  fpt;     //指纹ID

	uint8_t  attr;    //钥匙属性：永久、一次性、策略……
	uint8_t  week;    //钥匙策略：周几生效（为0表示当前策略类型为年月日策略）
	uint32_t stime;   //钥匙策略：起始时间
	uint32_t etime;   //钥匙策略：结束时间
	uint32_t ctime;   //钥匙创建时间
}NvFpt_stu_t;

/* 卡片数据（24byte） */
typedef struct
{
	uint8_t  card[CARD_LEN_MAX]; //卡片ID

	uint8_t  attr;     //钥匙属性：永久、一次性、策略……
	uint8_t  week;     //钥匙策略：周几生效（为0表示当前策略类型为年月日策略）
	uint32_t stime;    //钥匙策略：起始时间
	uint32_t etime;    //钥匙策略：结束时间
	uint32_t ctime;    //钥匙创建时间
}NvCard_stu_t;

/* 人脸数据（15byte） */
typedef struct
{
	uint8_t  faceID; 	//人脸ID

	uint8_t  attr;     //钥匙属性：永久、一次性、策略……
	uint8_t  week;     //钥匙策略：周几生效（为0表示当前策略类型为年月日策略）
	uint32_t stime;    //钥匙策略：起始时间
	uint32_t etime;    //钥匙策略：结束时间
	uint32_t ctime;    //钥匙创建时间
}NvFace_stu_t;

#if defined(PVN_SUPPORT)
typedef struct  
{
	uint8_t  pvnID;    //掌静脉ID
	uint8_t  attr;     //钥匙属性：永久、一次性、策略……
	uint8_t  week;     //钥匙策略：周几生效（为0表示当前策略类型为年月日策略）
	uint32_t stime;    //钥匙策略：起始时间
	uint32_t etime;    //钥匙策略：结束时间
	uint32_t ctime;    //钥匙创建时间
}NvPvn_stu_t;
#endif

#if defined (FINGERVEIN_SUPPORT)
typedef struct
{
	uint8_t  fvn;     //指静脉ID

	uint8_t  attr;    //钥匙属性：永久、一次性、策略……
	uint8_t  week;    //钥匙策略：周几生效（为0表示当前策略类型为年月日策略）
	uint32_t stime;   //钥匙策略：起始时间
	uint32_t etime;   //钥匙策略：结束时间
	uint32_t ctime;   //钥匙创建时间
}NvFvn_stu_t;
#endif

/* 凭证数据 */
#if defined (EVIDENCE_SUPPORT)
typedef struct
{
	uint8_t  Evidence[EVIDENCE_LEN_MAX];	//凭证值

	uint8_t  EvidenceId;    	//凭证ID
	uint8_t  EvidenceStatus;    //凭证状态
	uint8_t  attr;     			//凭证属性：永久、一次性、策略……
	uint8_t  week;    //钥匙策略：周几生效（为0表示当前策略类型为年月日策略）
	uint32_t stime;   			//生效时间
	uint32_t etime;   			//失效时间
	uint32_t ctime;   			//钥匙创建时间
}NvEvidence_stu_t;
#endif

typedef struct
{
	uint8_t fpt;             			//指纹数量（0~100组，为0表示禁用指纹）
	uint8_t pwd;             			//密码数量（1~50组）
	uint8_t card;            			//卡片数量（0~100组，为0表示禁用卡片）
    uint8_t face;            			//人脸数量（0~20组，为0表示禁用人脸）
	#if defined(FINGERVEIN_SUPPORT)
	uint8_t fvn;             			//指静脉数量（0~100组，为0表示禁用指静脉）
	#endif
	#if defined(PVN_SUPPORT)
	uint8_t pvn;						//掌静脉数量(1-50组,为0表示禁用掌静脉)
	#endif
	#if defined(EVIDENCE_SUPPORT)
	uint8_t evidence;					//掌静脉数量(1-20组,为0表示禁用凭证)
	#endif
}KeyQty_stu_t;

/* 用户参数（133byte） */
typedef struct
{
	uint8_t nvInitFlag;						//初始化标志 1 
	uint8_t activeCodeHash[20+1];			//激活码（byte0~19为激活码的SHA1值，byte20为激活标志）21
	NvOfflinePwm_stu_t offlinePwd;			//离线密码数据 30

	uint8_t admin_pwd[PWD_LEN_MAX]; 		//管理密码 12
	uint8_t dual_verify;					//双验证开关 1
	uint8_t urgentFlag;						//胁迫密码功能开关 1 Byte  0：关闭 1：打开
	uint8_t ate_flag;						//ATE配置锁参数
	uint8_t qty_ploy_pwd;					//策略密钥数量
	uint8_t reserved[14];           		//CPU卡片3DES加解密KEY 16

	KeyQty_stu_t qty;						//密钥数量 

	uint8_t pwd_map[KEYS_MAP_SIZE_PWD];		//密码位图 7
	uint8_t fpt_map[KEYS_MAP_SIZE_FPT];		//指纹位图 13
	uint8_t card_map[KEYS_MAP_SIZE_CARD];	//卡片位图 13
	uint8_t face_map[KEYS_MAP_SIZE_FACE];	//人脸位图 3
	#if defined(FINGERVEIN_SUPPORT)
	uint8_t fvn_map[KEYS_MAP_SIZE_FVN];		//指静脉位图 13
	#endif
	#if defined(PVN_SUPPORT)
	uint8_t pvn_map[KEYS_MAP_SIZE_PVN];		//掌静脉位图 7
	#endif
	#if defined(EVIDENCE_SUPPORT)
	uint8_t evidence_map[KEYS_MAP_SIZE_EVIDENCE];//凭证位图 3
	#endif
}UsersParam_stu_t;

typedef struct 
{
	UsersParam_stu_t usersParam;				//用户参数
	NvPassword_stu_t pwdData[KEYS_MAX_QTY_PWD];	//钥匙数据（密码库：50组*26byte） 	1300
	NvFpt_stu_t fptData[KEYS_MAX_QTY_FPT];		//钥匙数据（指纹库：100组*15byte） 	1500
	NvCard_stu_t cardData[KEYS_MAX_QTY_CARD];	//钥匙数据（卡片库：100组*24byte） 	2400
	NvFace_stu_t faceData[KEYS_MAX_QTY_FACE];	//钥匙数据（人脸库：20/50组*15byte）300/750
	#if defined(FINGERVEIN_SUPPORT)
	NvFvn_stu_t fvnData[KEYS_MAX_QTY_FVN];		//钥匙数据（指静脉库：100组*15byte） 1500
	#endif
	#if defined(PVN_SUPPORT)
	NvPvn_stu_t pvnData[KEYS_MAX_QTY_PVN];		//钥匙数据（掌静脉库： 50组*15byte）750
	#endif
	#if defined(EVIDENCE_SUPPORT)
	NvEvidence_stu_t evidenceData[KEYS_MAX_QTY_EVIDENCE];		//钥匙数据（凭证库： 20组*24byte）480
	#endif
}NvUsers_stu_t; //5629 Byte

#pragma pack()

/* USERS组件的NV大小 */
#define USARS_NV_SIZE (sizeof(NvUsers_stu_t) > 6000 ? sizeof(NvUsers_stu_t) : 6000) //为了兼容已出货的锁

__EFRAM static uint8_t offline_pwd_random[OFFLINE_PWD_RANDOM_LEN] = {0};//离线密码因子随机数 28字节

static UsersParam_stu_t gUsersParam;

/* 双验证情况下第一次验证的密匙类型 */
static uint8_t g_first_verify_keys_type;

/* 待删除的一次性密码信息 */
static uint8_t g_onceKeysType = 0XFF;
static uint8_t g_onceKeysNum = 0XFF;
static uint8_t g_isModifyAdmin = 0;//是否修改管理员密码标志
/* 胁迫密码前缀 */
const uint8_t urgentPwdPrefix[3] = {9,1,1};

/**
  * @brief  复位NV里面Users部分所有的数据
  *
  * @note   恢复出厂设置时调用
  */
static void Users_NvReset(void)
{
#if defined(DXTC_NO_MENU)
	uint8_t pwd[] = {0}; //没有初始管理密码
#else
	uint8_t pwd[] = DEFAULT_ADMIN_PWD; //初始管理密码赋值
#endif

	/* 用户参数恢复默认 */
	memset(&gUsersParam, 0, sizeof(gUsersParam));

	/* 置位NV标志 */
	gUsersParam.nvInitFlag = USARS_NV_INIT_FLAG;

	/* 恢复默认管理员密码 */
	memset(gUsersParam.admin_pwd, 0XFF, sizeof(gUsersParam.admin_pwd));
	memcpy(gUsersParam.admin_pwd, pwd, sizeof(pwd));

	/* 默认密钥数量 */
#if defined(ATE_CFG_LOCK_PARA)
	/* 首次上电未产测，默认都是0 */
#else
	gUsersParam.qty.fpt  = KOS_PARAM_USERS_QTY_FINGER;  // 指纹数量(0~100组，为0表示禁用指纹)
	gUsersParam.qty.pwd  = KOS_PARAM_USERS_QTY_PWD;	    // 密码数量(1~50组)
	gUsersParam.qty.card = KOS_PARAM_USERS_QTY_CARD;	// 卡片数量(0~100组，为0表示禁用卡片)
    gUsersParam.qty.face = KOS_PARAM_USERS_QTY_FACE;	// 人脸数量(0~100组，为0表示禁用卡片)
	#if defined(FINGERVEIN_SUPPORT)
	gUsersParam.qty.fvn  = KOS_PARAM_USERS_QTY_FINGERVEIN;  // 指静脉数量(0~100组，为0表示禁用指静脉)
	#endif
	#if defined(PVN_SUPPORT)
	gUsersParam.qty.pvn = KOS_PARAM_USERS_QTY_PVN;		// 掌静脉数量(0~50组，为0表示禁用掌静脉)
	#endif
	#if defined(EVIDENCE_SUPPORT)
	gUsersParam.qty.evidence = KOS_PARAM_USERS_QTY_EVIDENCE;	// 凭证数量0~20组，为0表示禁用凭证)
	#endif
#endif
	//保存user param
	OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam), &gUsersParam, sizeof(gUsersParam));
}

/**
  * @brief  用户组件初始化
  *         
  * @note   
  */
static void Users_Init(void)
{
	//读出用户数据
	OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, usersParam), &gUsersParam, sizeof(gUsersParam));
	USERS_LOG("gUsersParam.nvInitFlag = 0x%02x\r\n", gUsersParam.nvInitFlag);
    // gUsersParam.nvInitFlag =0;
	if(gUsersParam.nvInitFlag != USARS_NV_INIT_FLAG)//未初始化,进行初始化
	{
		USERS_LOG("Users_NvReset\r\n ");
		Users_NvReset();
	}

#if defined(ATE_CFG_LOCK_PARA) //加载密钥数量
	if (gUsersParam.ate_flag != USARS_NV_INIT_FLAG) //未产测，写一个默认值，兼容降本已出货的锁
	{
		gUsersParam.qty.fpt  = 100;
		gUsersParam.qty.pwd  = 60;
		gUsersParam.qty.card = 100;
		gUsersParam.qty.face = 50;
	#if defined(FINGERVEIN_SUPPORT)
		gUsersParam.qty.fvn  = 100;
	#endif
		#if defined(PVN_SUPPORT)
		gUsersParam.qty.pvn = 50;
		#endif
		#if defined(EVIDENCE_SUPPORT)
		gUsersParam.qty.evidence = 20;
		#endif
		gUsersParam.qty_ploy_pwd = 10; //用户密钥数量包括策略密钥，这里的策略密钥数量只为了限制app的下发
	}
#endif
	USERS_LOG("ate flag: %02x\r\n", gUsersParam.ate_flag);
	USERS_LOG("qty fpt: %d, pwd: %d(ploy_pwd: %d), card: %d, face: %d\r\n", gUsersParam.qty.fpt, gUsersParam.qty.pwd, gUsersParam.qty_ploy_pwd, gUsersParam.qty.card, gUsersParam.qty.face);
#if defined(FINGERVEIN_SUPPORT)
	USERS_LOG("qty fvn: %d\r\n", gUsersParam.qty.fvn);
#endif
#if defined(EVIDENCE_SUPPORT)
	USERS_LOG("evidence fvn: %d\r\n", gUsersParam.qty.evidence);
#endif
}

/**
  * @brief  获取对应秘钥类型的map的首地址
  * @note
  *
  * @param	keysType：秘钥类型
  * @return 返回对应map表首地址
  */
static uint8_t* Users_GetKeysMap(uint8_t keysType)
{
	switch (keysType)
	{
		case USERS_TYPE_PWD:
			return gUsersParam.pwd_map;
		case USERS_TYPE_FPT:
			return gUsersParam.fpt_map;
		case USERS_TYPE_CARD:
			return gUsersParam.card_map;
		case USERS_TYPE_FACE:
			return gUsersParam.face_map;
#if defined(FINGERVEIN_SUPPORT)
		case USERS_TYPE_FVN:
			return gUsersParam.fvn_map;
#endif
#if defined(PVN_SUPPORT)
		case USERS_TYPE_PVN:
			return gUsersParam.pvn_map;
#endif
#if defined(EVIDENCE_SUPPORT)
		case USERS_TYPE_EVIDENCE:
			return gUsersParam.evidence_map;
#endif
		default:
			return NULL;
	}
}

/**
  * @brief  获取对应秘钥类型的Data的在NV的存放首地址
  * @note
  *
  * @param	keysType：秘钥类型
  * @return 返回对应秘钥类型的Data的在NV的存放首地址
  */
static uint32_t Users_GetKeysDataAddr(uint8_t keysType)
{
	switch (keysType)
	{
		case USERS_TYPE_PWD:
			return OSAL_OFFSET(NvUsers_stu_t, pwdData);
		case USERS_TYPE_FPT:
			return OSAL_OFFSET(NvUsers_stu_t, fptData);
		case USERS_TYPE_CARD:
			return OSAL_OFFSET(NvUsers_stu_t, cardData);
		case USERS_TYPE_FACE:
			return OSAL_OFFSET(NvUsers_stu_t, faceData);
#if defined(FINGERVEIN_SUPPORT)
		case USERS_TYPE_FVN:
			return OSAL_OFFSET(NvUsers_stu_t, fvnData);
#endif
#if defined(PVN_SUPPORT)
		case USERS_TYPE_PVN:
			return OSAL_OFFSET(NvUsers_stu_t, pvnData);
#endif
#if defined(EVIDENCE_SUPPORT)
		case USERS_TYPE_EVIDENCE:
			return OSAL_OFFSET(NvUsers_stu_t, evidenceData);
#endif
		default:
			return 0;
	}
}

/**
  * @brief  获取对应秘钥类型的Data的在NV的存储总大小
  * @note
  *
  * @param	keysType：秘钥类型
  * @return 返回对应秘钥类型的Data的在NV的存储总大小
  */
static uint32_t Users_GetKeysDataSize(uint8_t keysType)
{
	switch (keysType)
	{
		case USERS_TYPE_PWD:
			return sizeof(NvPassword_stu_t) * KEYS_MAX_QTY_PWD;
		case USERS_TYPE_FPT:
			return sizeof(NvFpt_stu_t) * KEYS_MAX_QTY_FPT;
		case USERS_TYPE_CARD:
			return sizeof(NvCard_stu_t) * KEYS_MAX_QTY_CARD;
		case USERS_TYPE_FACE:
			return sizeof(NvFace_stu_t) * KEYS_MAX_QTY_FACE;
#if defined(FINGERVEIN_SUPPORT)
		case USERS_TYPE_FVN:
			return sizeof(NvFvn_stu_t) * KEYS_MAX_QTY_FVN;
#endif
#if defined(PVN_SUPPORT)
		case USERS_TYPE_PVN:
			return sizeof(NvPvn_stu_t) * KEYS_MAX_QTY_PVN;
#endif
#if defined(EVIDENCE_SUPPORT)
		case USERS_TYPE_EVIDENCE:
			return sizeof(NvEvidence_stu_t) * KEYS_MAX_QTY_EVIDENCE;
#endif
		default:
			return 0;
	}
}

/**
  * @brief  查找一个密钥ID,判断是否添加（占用）
  *
  * @param  keysType：密钥类型
  * @param  keysId：密钥编号（ID）
  * @return ID空闲返回SUCCESS   否则返回ERROR
  */
static ErrorStatus Users_FindKeys(uint8_t keysType, uint8_t keysId)
{
	uint8_t map = 0;

	if (keysType == USERS_TYPE_PWD && keysId < KEYS_QTY_PWD)
	{
		map = gUsersParam.pwd_map[keysId / 8];
	}
	else if (keysType == USERS_TYPE_FPT && keysId < KEYS_QTY_FPT)
	{
		map = gUsersParam.fpt_map[keysId / 8];
	}
	else if (keysType == USERS_TYPE_CARD && keysId < KEYS_QTY_CARD)
	{
		map = gUsersParam.card_map[keysId / 8];
	}
	else if (keysType == USERS_TYPE_FACE && keysId < KEYS_QTY_FACE)
	{
		map = gUsersParam.face_map[keysId / 8];
	}
#if defined(FINGERVEIN_SUPPORT)
	else if (keysType == USERS_TYPE_FVN && keysId < KEYS_QTY_FVN)
	{
		map = gUsersParam.fvn_map[keysId / 8];
	}
#endif
#if defined(PVN_SUPPORT)
	else if (keysType == USERS_TYPE_PVN && keysId < KEYS_QTY_PVN)
	{
		map = gUsersParam.pvn_map[keysId / 8];
	}
#endif
#if defined(EVIDENCE_SUPPORT)
	else if (keysType == USERS_TYPE_EVIDENCE && keysId < KEYS_QTY_EVIDENCE)
	{
		map = gUsersParam.evidence_map[keysId / 8];
	}
#endif
	else
	{
		return ERROR; //密钥类型或ID错误
	}
	if ((map & (1 << (keysId % 8))) == 0)
	{
		return SUCCESS; //该ID未占用：空闲
	}
	return ERROR; //该ID已占用
}

/**
  * @brief  读取一个密钥数据
  *
  * @param  keysType：密钥类型
  * @param  keysId：密钥编号（ID）
  * @param  pData：密钥数据
  * 
  * @return 读取成功返回SUCCESS  失败返回ERROR
  */
static ErrorStatus Users_ReadKeys(uint8_t keysType, uint8_t keysId, void *pData)
{
	uint32_t addr, len;

	if (keysType == USERS_TYPE_PWD && keysId < KEYS_QTY_PWD)
	{
		addr = OSAL_OFFSET(NvUsers_stu_t, pwdData[keysId]);
		len = sizeof(NvPassword_stu_t);
	}
	else if (keysType == USERS_TYPE_FPT && keysId < KEYS_QTY_FPT)
	{
		addr = OSAL_OFFSET(NvUsers_stu_t, fptData[keysId]);
		len = sizeof(NvFpt_stu_t);
	}
	else if (keysType == USERS_TYPE_CARD && keysId < KEYS_QTY_CARD)
	{
		addr = OSAL_OFFSET(NvUsers_stu_t, cardData[keysId]);
		len = sizeof(NvCard_stu_t);
	}
	else if (keysType == USERS_TYPE_FACE && keysId < KEYS_QTY_FACE)
	{
		addr = OSAL_OFFSET(NvUsers_stu_t, faceData[keysId]);
		len = sizeof(NvFace_stu_t);
	}
#if defined(FINGERVEIN_SUPPORT)
	else if (keysType == USERS_TYPE_FVN && keysId < KEYS_QTY_FVN)
	{
		addr = OSAL_OFFSET(NvUsers_stu_t, fvnData[keysId]);
		len = sizeof(NvFvn_stu_t);
	}
#endif
#if defined(PVN_SUPPORT)
	else if (keysType == USERS_TYPE_PVN && keysId < KEYS_QTY_PVN)
	{
		addr = OSAL_OFFSET(NvUsers_stu_t, pvnData[keysId]);
		len = sizeof(NvPvn_stu_t);
	}
#endif
#if defined(EVIDENCE_SUPPORT)
	else if (keysType == USERS_TYPE_EVIDENCE && keysId < KEYS_QTY_EVIDENCE)
	{
		addr = OSAL_OFFSET(NvUsers_stu_t, evidenceData[keysId]);
		len = sizeof(NvEvidence_stu_t);
	}
#endif
	else
	{
		return ERROR; //密钥类型或ID错误
	}
	return OSAL_NvRead(addr, pData, len);
}

/**
  * @brief  保存一个密钥数据
  *
  * @param  keysType：密钥类型
  * @param  keysId：密钥编号（ID）
  * @param  pData：密钥数据
  * 
  * @return 添加成功返回SUCCESS  失败返回ERROR
  */
static ErrorStatus Users_SaveKeys(uint8_t keysType, uint8_t keysId, void *pData)
{
	uint32_t addr, len;

	USERS_LOG("USERS_SaveKeys, keysType:%x,keysId:%x\r\n", keysType, keysId);

	if (keysType == USERS_TYPE_PWD && keysId < KEYS_QTY_PWD)
	{
		addr = OSAL_OFFSET(NvUsers_stu_t, pwdData[keysId]);
		len = sizeof(NvPassword_stu_t);
		gUsersParam.pwd_map[keysId / 8] |= 1 << (keysId % 8);
	}
	else if (keysType == USERS_TYPE_FPT && keysId < KEYS_QTY_FPT)
	{
		addr = OSAL_OFFSET(NvUsers_stu_t, fptData[keysId]);
		len = sizeof(NvFpt_stu_t);
		gUsersParam.fpt_map[keysId / 8] |= 1 << (keysId % 8);
	}
	else if (keysType == USERS_TYPE_CARD && keysId < KEYS_QTY_CARD)
	{
		addr = OSAL_OFFSET(NvUsers_stu_t, cardData[keysId]);
		len = sizeof(NvCard_stu_t);
		gUsersParam.card_map[keysId / 8] |= 1 << (keysId % 8);
	}
	else if (keysType == USERS_TYPE_FACE && keysId < KEYS_QTY_FACE)
	{
		addr = OSAL_OFFSET(NvUsers_stu_t, faceData[keysId]);
		len = sizeof(NvFace_stu_t);
		gUsersParam.face_map[keysId / 8] |= 1 << (keysId % 8);
	}
#if defined(FINGERVEIN_SUPPORT)
	else if (keysType == USERS_TYPE_FVN && keysId < KEYS_QTY_FVN)
	{
		addr = OSAL_OFFSET(NvUsers_stu_t, fvnData[keysId]);
		len = sizeof(NvFvn_stu_t);
		gUsersParam.fvn_map[keysId / 8] |= 1 << (keysId % 8);
	}
#endif
#if defined(PVN_SUPPORT)
else if (keysType == USERS_TYPE_PVN && keysId < KEYS_QTY_PVN)
	{
		addr = OSAL_OFFSET(NvUsers_stu_t, pvnData[keysId]);
		len = sizeof(NvPvn_stu_t);
		gUsersParam.pvn_map[keysId / 8] |= 1 << (keysId % 8);
	}
#endif
#if defined(EVIDENCE_SUPPORT)
else if (keysType == USERS_TYPE_EVIDENCE && keysId < KEYS_QTY_EVIDENCE)
	{
		addr = OSAL_OFFSET(NvUsers_stu_t, evidenceData[keysId]);
		len = sizeof(NvEvidence_stu_t);
		gUsersParam.evidence_map[keysId / 8] |= 1 << (keysId % 8);
	}
#endif
	else
	{
		return ERROR; //密钥类型或ID错误
	}

	//保存user param
	OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam), &gUsersParam, sizeof(gUsersParam));

	//保存密钥
	return OSAL_NvWrite(addr, pData, len);
}

/**
  * @brief  删除密钥数据
  *
  * @param  keysType：密钥类型
  * @param  keysId：密钥编号（ID）
  * 
  * @return 删除成功返回SUCCESS  失败返回ERROR
  */
static ErrorStatus Users_DeleteKeys(uint8_t keysType, uint8_t keysId)
{
	if(Users_FindKeys(keysType, keysId) == SUCCESS)
	{
		return ERROR; //不存在的密钥编号不能删除
	}
	if (keysType == USERS_TYPE_PWD && keysId < KEYS_QTY_PWD)
	{
		gUsersParam.pwd_map[keysId / 8] &= ~(1 << (keysId % 8));
	}
	else if (keysType == USERS_TYPE_FPT && keysId < KEYS_QTY_FPT)
	{
		gUsersParam.fpt_map[keysId / 8] &= ~(1 << (keysId % 8));
	}
	else if (keysType == USERS_TYPE_CARD && keysId < KEYS_QTY_CARD)
	{
		gUsersParam.card_map[keysId / 8] &= ~(1 << (keysId % 8));
	}
	else if (keysType == USERS_TYPE_FACE && keysId < KEYS_QTY_FACE)
	{
		gUsersParam.face_map[keysId / 8] &= ~(1 << (keysId % 8));
	}
#if defined(FINGERVEIN_SUPPORT)
	else if (keysType == USERS_TYPE_FVN && keysId < KEYS_QTY_FVN)
	{
		gUsersParam.fvn_map[keysId / 8] &= ~(1 << (keysId % 8));
	}
#endif
#if defined(PVN_SUPPORT)
	else if (keysType == USERS_TYPE_PVN && keysId < KEYS_QTY_PVN)
	{
		gUsersParam.pvn_map[keysId / 8] &= ~(1 << (keysId % 8));
	}
#endif
#if defined(EVIDENCE_SUPPORT)
else if (keysType == USERS_TYPE_EVIDENCE && keysId < KEYS_QTY_EVIDENCE)
	{
		gUsersParam.evidence_map[keysId / 8] &= ~ (1 << (keysId % 8));
	}
#endif
	else
	{
		return ERROR; //密钥类型或ID错误
	}

	//保存system_param
	return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam), &gUsersParam, sizeof(gUsersParam));
}

/**
  * @brief  删除多个密钥数据
  *
  * @param  keysType：密钥类型
  *
  * @return 添加成功返回SUCCESS  失败返回ERROR
  */
static ErrorStatus Users_DeleteMultiKeys(uint8_t keysType)
{
	USERS_LOG("Users_DeleteMultiKeys, keysType = %d\r\n", keysType);
	if (keysType == 0XFF) //清空所有密钥
	{
#if defined(DXTC_NO_MENU)
	    uint8_t pwd[] = {0}; //没有初始管理密码
#else
	    uint8_t pwd[] = DEFAULT_ADMIN_PWD; //初始管理密码赋值
#endif
		memset(gUsersParam.pwd_map, 0, KEYS_MAP_SIZE_PWD);
		memset(gUsersParam.fpt_map, 0, KEYS_MAP_SIZE_FPT);
		memset(gUsersParam.card_map, 0, KEYS_MAP_SIZE_CARD);
		memset(gUsersParam.face_map, 0, KEYS_MAP_SIZE_FACE);
	#if defined(FINGERVEIN_SUPPORT)
		memset(gUsersParam.fvn_map, 0, KEYS_MAP_SIZE_FVN);
	#endif
	#if defined(PVN_SUPPORT)
		memset(gUsersParam.pvn_map, 0, KEYS_MAP_SIZE_PVN);
	#endif
	#if defined(EVIDENCE_SUPPORT)
		memset(gUsersParam.evidence_map, 0, KEYS_MAP_SIZE_EVIDENCE);
	#endif
		
		/* 恢复默认管理员密码 */
		memset(gUsersParam.admin_pwd, 0XFF, PWD_LEN_MAX);
		memcpy(gUsersParam.admin_pwd, pwd, sizeof(pwd));

		/* 清空离线因子 */
	#if defined(DXTC_NO_MENU)
		memset((uint8_t *)&gUsersParam.offlinePwd, 0x00, sizeof(NvOfflinePwm_stu_t));
	#endif
	}
	else if (keysType == USERS_TYPE_PWD)
	{
		memset(gUsersParam.pwd_map, 0, KEYS_MAP_SIZE_PWD);
	}
	else if (keysType == USERS_TYPE_FPT)
	{
		#if defined(ADMIN_FPT_DISABLE)
		memset(gUsersParam.fpt_map, 0, KEYS_MAP_SIZE_FPT);
		#else
		uint8_t admin_finger = gUsersParam.fpt_map[0] & 0x01;
		memset(gUsersParam.fpt_map, 0, KEYS_MAP_SIZE_FPT);
		gUsersParam.fpt_map[0] = admin_finger; //保留管理指纹
		#endif
		
	}
	else if (keysType == USERS_TYPE_CARD)
	{
		memset(gUsersParam.card_map, 0, KEYS_MAP_SIZE_CARD);
	}
	else if (keysType == USERS_TYPE_FACE)
	{
		memset(gUsersParam.face_map, 0, KEYS_MAP_SIZE_FACE);
	}
#if defined(FINGERVEIN_SUPPORT)
	else if (keysType == USERS_TYPE_FVN)
	{
		uint8_t admin_fingervein = gUsersParam.fvn_map[0] & 0x01;
		memset(gUsersParam.fvn_map, 0, KEYS_MAP_SIZE_FVN);
		gUsersParam.fvn_map[0] = admin_fingervein; //保留管理指静脉
	}
#endif
#if defined(PVN_SUPPORT)
	else if (keysType == USERS_TYPE_PVN)
	{
		uint8_t admin_pvn = gUsersParam.pvn_map[0] & 0x01;
		memset(gUsersParam.pvn_map, 0, KEYS_MAP_SIZE_PVN);
		gUsersParam.pvn_map[0] = admin_pvn; //保留管理掌静脉
	}
#endif
#if defined(EVIDENCE_SUPPORT)
	else if (keysType == USERS_TYPE_EVIDENCE)
	{
		uint8_t admin_evidence = gUsersParam.evidence_map[0] & 0x01;
		memset(gUsersParam.evidence_map, 0, KEYS_MAP_SIZE_EVIDENCE);
		// gUsersParam.evidence_map[0] = admin_evidence; //不保留管理掌静脉
	}
#endif
	else
	{
		return ERROR;
	}

	//保存system_param
	return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam), &gUsersParam, sizeof(gUsersParam));
}

/**
  * @brief  修改管理员密码
  *
  * @param  pData：密码数据
  * @param  len：密码长度
  * 
  * @return 修改成功返回SUCCESS, 失败返回ERROR
  */
static ErrorStatus Users_ModifyAdminPassword(uint8_t *pData, uint8_t len)
{
	memset(gUsersParam.admin_pwd, 0XFF, PWD_LEN_MAX);
	memcpy(gUsersParam.admin_pwd, pData, len);

	/* 保存系统参数 */
	return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam.admin_pwd), &gUsersParam.admin_pwd, sizeof(gUsersParam.admin_pwd));
}

/**
  * @brief  读取管理员密码
  *
  * @param  pData：密码数据
  * 
  * @return 修改成功返回SUCCESS, 失败返回ERROR
  */
static ErrorStatus Users_ReadAdminPassword(void *pData)
{
	memcpy(pData,gUsersParam.admin_pwd,PWD_LEN_MAX);
	return SUCCESS;
}


/**
  * @brief  读取激活码
  *
  * @param  pStr：数据指针
  * 
  * @return 成功返回SUCCESS, 失败返回ERROR
  */
static ErrorStatus Users_ReadActivationCode(uint8_t *pStr)
{
	uint8_t tmpBuf[20 + 1]={0}, i;

	memcpy(tmpBuf, gUsersParam.activeCodeHash, sizeof(tmpBuf));
	for (i = 0; i < sizeof(tmpBuf); i++)
	{
		if (tmpBuf[i] != 0)
		{
			break; //激活码存在
		}
	}

	if (pStr != NULL && i < sizeof(tmpBuf))
	{
		memcpy(pStr, tmpBuf, sizeof(tmpBuf));
	}

    if (i < sizeof(tmpBuf))
    {
        return SUCCESS; //激活码存在
    }
	return ERROR;    //激活码不存在
}

/**
  * @brief  写激活码，将6字节激活码经过哈希后存到EEPROM
  *
  * @param  pCode：数据指针
  * @param  len：数据长度
  * 
  * @return 成功返回SUCCESS, 失败返回ERROR
  */
static ErrorStatus Users_WriteActivationCode(uint8_t *pCode, uint8_t len)
{
	uint8_t digest[20 + 1] = {0};
	uint8_t string[7]="";

	if (len != 6)
	{
		return ERROR;
	}
	if (OSAL_Crypto(CALC_SHA1, pCode, len, digest, NULL) == ERROR)
	{
		return ERROR;
	}
    memcpy(string, pCode, 6);
    USERS_LOG("USERS_WriteActivationCode [%s]\r\n", string);
	// for (int i=0; i<21; i++)
	// {
	//     USERS_LOG("%02X\r\n", digest[i]);
	// }
    memcpy(gUsersParam.activeCodeHash, digest, sizeof(digest));
	return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam.activeCodeHash), &gUsersParam.activeCodeHash, sizeof(gUsersParam.activeCodeHash));
}


//读离线密码随机数
static ErrorStatus Users_ReadOfflinePwdRandom(uint8_t *random, uint8_t len)
{
    return OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, usersParam.offlinePwd.random), random, len);
}

//保存离线密码随机数
static ErrorStatus Users_SaveOfflinePwdRandom(uint8_t *random, uint8_t len)
{
    return OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, usersParam.offlinePwd.random), random, len);
}

/**
  * @brief  获取密钥的实际长度
  * @note   密钥的最大长度如果不是最大长度，后面都是填充0XFF
  *
  * @param  pData：buf数据指针
  * @param  maxLen：密钥最大长度
  * 
  * @return 有效密码长度
  */
static uint8_t Users_GetKeysLen(uint8_t *pData, uint8_t maxLen)
{
	for (int i = 0; i < maxLen; i++)
	{
		if (pData[i] == 0XFF)
		{
			return i;
		}
	}
	return maxLen;
}

/**
  * @brief  检测是否为有效密码
  * @note
  *
  * @param  pData：密码数据指针
  * @param  len：密码长度
  * 
  * @return 正常返回SUCCESS
  */
static ErrorStatus Users_IsValidPassword(uint8_t *pData, uint8_t len)
{
	for (int i = 0; i < len; i++)
	{
		if (pData[i] > 9)
		{
			return ERROR;
		}
	}
	return SUCCESS;
}

/**
  * @brief  判断密码是否太简单
  * @note   简单密码：连续递增、递减的密码、每位密码都相同、密码长度小于PWD_LEN_MIN
  *
  * @param pPassword:密码
  * @param len:密码长度
  * 
  * @return 简单返回SUCCESS  复杂返回ERROR
  */
static ErrorStatus Users_PasswordIsEasy(uint8_t *pPassword, uint8_t len)
{
	uint8_t cnt1 = 1, cnt2 = 1, cnt3 = 1;

	if (len < PWD_LEN_MIN)
	{
		return SUCCESS;
	}
	for (int i = 1; i < len; i++)
	{
		cnt1 = (pPassword[i - 1] == pPassword[i]) ? (cnt1 + 1) : 1;
		cnt2 = (pPassword[i - 1] == pPassword[i] - 1) ? (cnt2 + 1) : 1;
		cnt3 = (pPassword[i - 1] == pPassword[i] + 1) ? (cnt3 + 1) : 1;
	}
	return (cnt1 == len || cnt2 == len || cnt3 == len) ? SUCCESS : ERROR;
}

/**
  * @brief  内存比对
  * @note   必须满足 maxLen >= minLen
  *
  * @param  pMinData：短BUF的数据指针
  * @param  minLen：  短BUF的数据长度
  * @param  pMaxData：长BUF的数据指针
  * @param  maxLen：  长BUF的数据长度
  * @param  opt：     1使能模糊比较
	*                 0禁止模糊比较

  * @return 两BUF内容相同返回SUCCESS 否则返回ERROR
  */
static ErrorStatus Users_MemoryCmp(uint8_t *pMinData, uint8_t minLen, uint8_t *pMaxData, uint8_t maxLen, uint8_t opt)
{
	uint8_t i = 0;
	uint8_t offset = 0;

	if (maxLen < minLen || minLen == 0)
	{
		return ERROR;
	}
	while ((i < minLen) && ((i + offset) < maxLen))
	{
		if (pMinData[i] != pMaxData[i + offset])
		{
			if (opt == 0)
			{
				return ERROR;
			}
			i = 0;
			offset++;
		}
		else
		{
			i++;
		}
	}
	if (opt == 0)
	{
        return (minLen == maxLen) ? SUCCESS : ERROR;
	}
	else
	{
        return (i == minLen) ? SUCCESS : ERROR;
	}
}


/**
 * @brief 更新密钥状态
 * 
 * @param [in] keysType 密钥状态
 * @param [in] evidId 凭证ID
 * @param [in] status 状态
 * @param [in] updataType 更新状态，0xff 全部更新  或者 0 单个更新
 * @return uint8_t 
 * 
 * @note 成功返回SUCCESS，失败返回ERROR
 */
static uint8_t Users_updata_keys_status(uint8_t keysType, uint8_t evidId, uint8_t status, uint8_t updataType)
{
	NvEvidence_stu_t evidenceData = {0};
	uint8_t result = ERROR;

	if (keysType == USERS_TYPE_EVIDENCE)
	{
		for (int id = 0; id < KEYS_QTY_EVIDENCE; id++)
		{
			if (gUsersParam.evidence_map[id / 8] & (1 << (id % 8)))
			{
				Users_ReadKeys(USERS_TYPE_EVIDENCE, id, &evidenceData);

				if(updataType == 0)
				{
					if (evidenceData.EvidenceId == evidId)
					{
						evidenceData.EvidenceStatus = status;

						result = Users_SaveKeys(USERS_TYPE_EVIDENCE, id, &evidenceData);
						return result;
					}
				}
				else if(updataType == 0xff)
				{
					if(Users_FindKeys(USERS_TYPE_EVIDENCE, id) == ERROR)
					{
						evidenceData.EvidenceStatus = status;
						result = Users_SaveKeys(USERS_TYPE_EVIDENCE, id, &evidenceData);
						if(result == ERROR)
						{
							return result;
						}
					}
				}
				
			}
		}
	}
	return result;
}
/**
  * @brief  输入的密钥 与 密钥库进行匹配
  * @note
  *
  * @param  keysType：密钥类型
  * @param  pData：输入数据
  * @param  len：输入数据长度
  * @param  opt：1使能模糊比较
  *              0禁止模糊比较
  * 
  * @return 匹配成功：返回密钥ID, 否则返回0XFF
  */
static uint8_t Users_MatchKeysLibrary(uint8_t keysType, uint8_t *pData, uint8_t len, uint8_t opt, void *keys_data)
{
	if (keysType == USERS_TYPE_PWD)
	{
		for (int id = 0; id < KEYS_QTY_PWD; id++)
		{
			if (gUsersParam.pwd_map[id / 8] & (1 << (id % 8)))
			{
				NvPassword_stu_t pwdData = {0};
				uint8_t keysLen;

				Users_ReadKeys(USERS_TYPE_PWD, id, &pwdData);
				keysLen = Users_GetKeysLen(pwdData.pwd, PWD_LEN_MAX);
				if (Users_MemoryCmp(pwdData.pwd, keysLen, pData, len, opt) == SUCCESS)
				{
					memcpy(keys_data, &pwdData, sizeof(pwdData));
					return id;
				}
			}
		}
	}
	else if (keysType == USERS_TYPE_FPT)
	{
		for (int id = 0; id < KEYS_QTY_FPT; id++)
		{
			if (gUsersParam.fpt_map[id / 8] & (1 << (id % 8)))
			{
				NvFpt_stu_t fptData = {0};

				Users_ReadKeys(USERS_TYPE_FPT, id, &fptData);
				if (fptData.fpt == pData[0])
				{
					memcpy(keys_data, &fptData, sizeof(fptData));
					return id;
				}
			}
		}
	}
	else if (keysType == USERS_TYPE_CARD)
	{
		for (int id = 0; id < KEYS_QTY_CARD; id++)
		{
			if (gUsersParam.card_map[id / 8] & (1 << (id % 8)))
			{
				NvCard_stu_t cardData = {0};

				Users_ReadKeys(USERS_TYPE_CARD, id, &cardData);
				if (Users_MemoryCmp(cardData.card, len, pData, len, 0) == SUCCESS)
				{
					memcpy(keys_data, &cardData, sizeof(cardData));
					return id;
				}
			}
		}
	}
	else if (keysType == USERS_TYPE_FACE)
	{
		for (int id = 0; id < KEYS_QTY_FACE; id++)
		{
			if (gUsersParam.face_map[id / 8] & (1 << (id % 8)))
			{
				NvFace_stu_t faceData = {0};
				Users_ReadKeys(USERS_TYPE_FACE, id, &faceData);
				
				if (faceData.faceID == pData[0])
				{
					memcpy(keys_data, &faceData, sizeof(faceData));
					return id;
				}
			}
		}
	}
#if defined(FINGERVEIN_SUPPORT)
	else if (keysType == USERS_TYPE_FVN)
	{
		for (int id = 0; id < KEYS_QTY_FVN; id++)
		{
			if (gUsersParam.fvn_map[id / 8] & (1 << (id % 8)))
			{
				NvFvn_stu_t fvnData = {0};

				Users_ReadKeys(USERS_TYPE_FVN, id, &fvnData);
				if (fvnData.fvn == pData[0])
				{
					memcpy(keys_data, &fvnData, sizeof(fvnData));
					return id;
				}
			}
		}
	}
#endif
#if defined(PVN_SUPPORT)
	else if (keysType == USERS_TYPE_PVN)
	{
		for (int id = 0; id < KEYS_QTY_PVN; id++)
		{
			if (gUsersParam.pvn_map[id / 8] & (1 << (id % 8)))
			{
				NvPvn_stu_t pvnData = {0};

				Users_ReadKeys(USERS_TYPE_PVN, id, &pvnData);
				if (pvnData.pvnID == pData[0])
				{
					memcpy(keys_data, &pvnData, sizeof(pvnData));
					return id;
				}
			}
		}
	}
#endif
#if defined(EVIDENCE_SUPPORT)
	else if (keysType == USERS_TYPE_EVIDENCE)
	{
		for (int id = 0; id < KEYS_QTY_EVIDENCE; id++)
		{
			if (gUsersParam.evidence_map[id / 8] & (1 << (id % 8)))
			{
				NvEvidence_stu_t evidenceData = {0};

				Users_ReadKeys(USERS_TYPE_EVIDENCE, id, &evidenceData);
				if(opt == 1)	//添加和删除凭证时，此参数为1，表示只对比ID，为0时表示对比凭证值
				{
					if (evidenceData.EvidenceId == pData[0])
					{
						memcpy(keys_data, &evidenceData, sizeof(evidenceData));
						return id;
					}
				}
				else
				{
					if (memcmp(evidenceData.Evidence, pData, len) == 0)
					{
						memcpy(keys_data, &evidenceData, sizeof(evidenceData));
						if(evidenceData.EvidenceStatus == 0x01)//冻结凭证
						{
							USERS_LOG("Users_MatchKeysLibrary USERS_ID_RFEEZE id:%d\n",id);
							return USERS_ID_RFEEZE;
						}
						return id;
					}
				}
			}
		}
	}
#endif
	return 0XFF;
}

/**
  * @brief  验证是否为胁迫密码
  * @note
  *
  * @param  keysType：密钥类型
  * @param  keysId：密钥编号（ID）
  * @param  pData：输入数据
  * @param  len：输入数据长度
  * 
  * @return 若为胁迫密码则返回SET,否则返回RESET
  */
static FlagStatus Users_UrgentVerify(uint8_t keysType, uint8_t keysId, uint8_t *pData, uint8_t len)
{
	if(keysType == USERS_TYPE_PWD)
	{
		NvPassword_stu_t pwdData = {0};
		uint8_t keysLen, urgentPwdPrefixLen;

		if(keysId == USERS_ID_ADMIN)//验证是否为胁迫前缀+管理密码
		{
			keysLen = Users_GetKeysLen(gUsersParam.admin_pwd, PWD_LEN_MAX);
			memcpy(pwdData.pwd, gUsersParam.admin_pwd, keysLen);
		}
		else//验证是否为胁迫前缀+普通密码
		{
			Users_ReadKeys(USERS_TYPE_PWD, keysId, &pwdData);
			keysLen = Users_GetKeysLen(pwdData.pwd, PWD_LEN_MAX);
		}
        urgentPwdPrefixLen = sizeof(urgentPwdPrefix) / sizeof(uint8_t);
		
        /* 胁迫密码前缀对比 */
        uint8_t AllPwdDdata[PWD_LEN_MAX + 3];
        memcpy(AllPwdDdata, urgentPwdPrefix, urgentPwdPrefixLen);
        memcpy(AllPwdDdata + urgentPwdPrefixLen, pwdData.pwd, keysLen);

        if (Users_MemoryCmp(AllPwdDdata, (keysLen + urgentPwdPrefixLen), pData, len, 1) == SUCCESS)
        {
            USERS_LOG("*****This is Urgent code\r\n");
            return SET;
        }
	}
	return RESET;
}

/**
  * @brief  比较2个时间的大小
  *
  * @note   时间格式：年月日时分秒
  *
  * @param
  * @return pMaxTime >= pMinTime 返回SUCCESS，否则返回ERROR
  */
static ErrorStatus Users_CmpTimeMaxMin(uint8_t *pMaxTime, uint8_t *pMinTime, uint8_t start, uint8_t end)
{
	uint8_t i;

	for (i=start; i<=end; i++)//只需判断到“分”即可，秒不用判断
	{
		if (pMaxTime[i] > pMinTime[i])
		{
			return SUCCESS;
		}
		else if (pMaxTime[i] < pMinTime[i])
		{
			return ERROR;
		}
	}
	return SUCCESS;
}

/**
  * @brief  检查当前时间是否在符合周策略要求
  *
  * @param  weekPloy: BIT:   7    6   5   4   3   2   1   0
  *                  星期：  /    六  五  四  三   二  一  日
  *
  * @return 满足要求返回SUCCESS
  */
static ErrorStatus Users_PloyCheckWeek(uint8_t weekPloy, uint32_t pStartTime, uint32_t pEndTime, int16_t time_zone)
{
	uint8_t week, y,m,d;
	uint8_t curDateTime[6];
	uint8_t sDateTime[6];
	uint8_t eDateTime[6];
    uint32_t cur_time = 0;

    // 修改时间（+时区）--比对时间区域
    OSAL_TimeGet(&cur_time, T_UTC);
    USERS_LOG("time_zone:%04X\r\n", time_zone);

    cur_time += time_zone * 900;
    OSAL_UTC2Time(cur_time, curDateTime);

	y = curDateTime[0];
	m = curDateTime[1];
	d = curDateTime[2];

	/* 基姆拉尔森计算公式计算星期几 */
	if (m == 1 || m == 2)
	{
		m += 12;
		y--;
  	}
	week = (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400) % 7 + 1;
	week = (week == 7) ? 0 : week;//将周日转换成0

	USERS_LOG("cur week: %d, weekPloy = %d\r\n", week, weekPloy);
	if (weekPloy & (1 << week))
	{
		OSAL_UTC2Time(pStartTime, sDateTime);
		OSAL_UTC2Time(pEndTime, eDateTime);

		USERS_LOG("Cur time: y = %d, m = %d, d = %d ,hour = %d, min = %d\r\n", 
			curDateTime[0], curDateTime[1], curDateTime[2], curDateTime[3], curDateTime[4]);
		USERS_LOG("Start time: y = %d, m = %d, d = %d ,hour = %d, min = %d\r\n", 
				sDateTime[0], sDateTime[1], sDateTime[2], sDateTime[3], sDateTime[4]);
		USERS_LOG("End time: y = %d, m = %d, d = %d ,hour = %d, min = %d\r\n", 
				eDateTime[0], eDateTime[1], eDateTime[2], eDateTime[3], eDateTime[4]);
		if (Users_CmpTimeMaxMin(curDateTime, sDateTime, 3, 4) == SUCCESS)
		{
			if (Users_CmpTimeMaxMin(eDateTime, curDateTime, 3, 4) == SUCCESS)
			{
				return SUCCESS;
			}
		}
	}
	return ERROR;
}

/**
  * @brief  检查当前时间是否在 pStartTime ~ pEndTime 范围内
  * @note   只检查：年月日时分
  * @return 在范围内返回SUCCESS
  */
static ErrorStatus Users_PloyCheckTime(uint32_t pStartTime, uint32_t pEndTime, int16_t time_zone)
{
	uint8_t curDateTime[6];
	uint8_t sDateTime[6];
	uint8_t eDateTime[6];
    uint32_t cur_time = 0;

    // 修改时间（+时区）--比对时间区域
    OSAL_TimeGet(&cur_time, T_UTC);
    USERS_LOG("time_zone:%04X\r\n", time_zone);
    cur_time += time_zone * 900;
    
    OSAL_UTC2Time(cur_time, curDateTime);
	OSAL_UTC2Time(pStartTime, sDateTime);
	OSAL_UTC2Time(pEndTime, eDateTime);

	USERS_LOG("Cur time: y = %d, m = %d, d = %d ,hour = %d, min = %d\r\n", 
			curDateTime[0], curDateTime[1], curDateTime[2], curDateTime[3], curDateTime[4]);
	USERS_LOG("Start time: y = %d, m = %d, d = %d ,hour = %d, min = %d\r\n", 
			sDateTime[0], sDateTime[1], sDateTime[2], sDateTime[3], sDateTime[4]);
	USERS_LOG("End time: y = %d, m = %d, d = %d ,hour = %d, min = %d\r\n", 
			eDateTime[0], eDateTime[1], eDateTime[2], eDateTime[3], eDateTime[4]);

	if (Users_CmpTimeMaxMin(curDateTime, sDateTime, 0, 4) == SUCCESS)
	{
		if (Users_CmpTimeMaxMin(eDateTime, curDateTime, 0, 4) == SUCCESS)
		{
			return SUCCESS;
		}
	}
	return ERROR;
}

/**
  * @brief  核对策略
  *
  * @param  pData：策略数据指针
  * @return SUCCESS策略通过，ERROR策略不通过
  */
static ErrorStatus Users_PloyCheck(UserPloy_stu_t *pData,uint8_t attr, int16_t time_zone)
{
	USERS_LOG("week:%d\r\n", pData->week);		//钥匙策略：周几生效（为0表示当前策略类型为年月日策略）
	USERS_LOG("stime:%ld\r\n", pData->stime);	//钥匙策略：起始时间
	USERS_LOG("etime:%ld\r\n", pData->etime);	//钥匙策略：结束时间

	if(attr == USERS_ATTR_PLOY)					//时间计划策略
	{
		return Users_PloyCheckTime(pData->stime, pData->etime, time_zone);
	}
	else if (attr == USERS_ATTR_WEEK)		  	//周计划策略
	{
		return Users_PloyCheckWeek(pData->week, pData->stime, pData->etime, time_zone);
	}
	else if (attr == USERS_ATTR_ONCE_PLOY)		  	//一次性密码+时间策略
	{
		return Users_PloyCheckTime(pData->stime, pData->etime, time_zone);
	}	
	else
	{
		return ERROR;
	}
}

/**
  * @brief  读取一条策略
  * @note   只有手机APP才会读取
  *
  * @param  ployNum：策略编号
  * @param  pData：策略数据指针
  * @return 成功、失败
  */
static ErrorStatus Users_PloyRead(uint8_t keysType, uint8_t keysNum, UserPloy_stu_t *pPloy)
{
	if(pPloy == NULL)
	{
		return ERROR;
	}
	
	if(Users_FindKeys(keysType, keysNum) == SUCCESS)
	{
		return ERROR; //不存在的密钥编号不能读取
	}

	if(keysType == USERS_TYPE_PWD)
	{
		if(keysNum >= KEYS_QTY_PWD)
		{
			return ERROR;
		}
		else
		{
			return OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, pwdData[keysNum].week), pPloy, sizeof(UserPloy_stu_t));
		}
	}
	else if(keysType == USERS_TYPE_FPT)
	{
		if(keysNum >= KEYS_QTY_FPT)
		{
			return ERROR;
		}
		else
		{
			return OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, fptData[keysNum].week), pPloy, sizeof(UserPloy_stu_t));
		}
	}
	else if(keysType == USERS_TYPE_CARD)
	{
		if(keysNum >= KEYS_QTY_CARD)
		{
			return ERROR;
		}
		else
		{
			return OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, cardData[keysNum].week), pPloy, sizeof(UserPloy_stu_t));
		}
	}
	else if(keysType == USERS_TYPE_FACE)
	{
		if(keysNum >= KEYS_QTY_FACE)
		{
			return ERROR;
		}
		else
		{
			return OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, faceData[keysNum].week), pPloy, sizeof(UserPloy_stu_t));
		}
	}
#if defined(FINGERVEIN_SUPPORT)
	else if(keysType == USERS_TYPE_FVN)
	{
		if(keysNum >= KEYS_QTY_FVN)
		{
			return ERROR;
		}
		else
		{
			return OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, fvnData[keysNum].week), pPloy, sizeof(UserPloy_stu_t));
		}
	}
#endif
#if defined(PVN_SUPPORT)
	else if(keysType == USERS_TYPE_PVN)
	{
		if(keysNum >= KEYS_QTY_PVN)
		{
			return ERROR;
		}
		else
		{
			return OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, pvnData[keysNum].week), pPloy, sizeof(UserPloy_stu_t));
		}
	}
#endif

#if defined(EVIDENCE_SUPPORT)
	else if(keysType == USERS_TYPE_EVIDENCE)
	{
		if(keysNum >= KEYS_QTY_EVIDENCE)
		{
			return ERROR;
		}
		else
		{
			return OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, evidenceData[keysNum].week), pPloy, sizeof(UserPloy_stu_t));
		}
	}
#endif
	else
	{
		return ERROR;
	}
}

/**
  * @brief  策略密码开门时，调用该函数判断密钥的策略是否ok
  *
  * @note   根据密钥编号，查找整个策略表
  * @param  keysType：密钥类型
  * @param  keysNum： 密钥编号
  *
  * @return 有匹配ok的策略，返回SUCCESS，否则返回ERROR
  */
static ErrorStatus Users_PloyMatch(uint8_t keysType, uint8_t keysNum,uint8_t attr, int16_t time_zone)
{
	UserPloy_stu_t ployData;

	if (Users_PloyRead(keysType, keysNum, &ployData) == SUCCESS)
	{
		return Users_PloyCheck(&ployData,attr, time_zone);
	}
	return ERROR;
}


/**
  * @brief  核对开锁密钥的属性
  * @note
  *
  * @param  attr：密钥属性
  * @param  keysType：密钥类型
  * @param  keysNum：密钥编号
  * 
  * @return 有权限开锁返回SUCCESS
  */
static ErrorStatus Users_CheckOpenLockKeysAttr(uint8_t attr, uint8_t keysType, uint8_t keysNum, int16_t time_zone)
{
	g_onceKeysType = 0XFF;
	g_onceKeysNum = 0XFF;

	if (attr == USERS_ATTR_FOREVER || attr == USERS_ATTR_ADMIN)
	{
		return SUCCESS;
	}
	else if (attr == USERS_ATTR_URGENT)
	{
		/* 紧急（胁迫）用户开锁，发消息给应用层 */
		UsersMsg_t usersmsg;
		usersmsg.ID = USERS_MSG_ID_URGENT;
		usersmsg.keysNum = keysNum;
		OSAL_MessagePublish(&usersmsg, sizeof(usersmsg));
		return SUCCESS;
	}
	else if (attr == USERS_ATTR_ONCE || attr == USERS_ATTR_ONCE_PLOY)
	{
		if (gUsersParam.dual_verify)//打开了安全模式
		{
			return ERROR; //安全模式，一次性密码不允许开锁
		}

		if (attr == USERS_ATTR_ONCE_PLOY)
		{
			if (Users_PloyMatch(keysType, keysNum, attr, time_zone) != SUCCESS)
			{
				return ERROR;
			}
		}
		g_onceKeysType = keysType;
		g_onceKeysNum = keysNum; //先暂存，等开锁成功后再删除这个keys
		return SUCCESS;
	}
	else if (attr == USERS_ATTR_PLOY || attr == USERS_ATTR_WEEK)//验证策略
	{
		return Users_PloyMatch(keysType, keysNum,attr, time_zone);
	}
	return ERROR;
}

/**
  * @brief  密码比对
  * @note   
  * @param  pData：  要比对的密码数据
  * @param  pwdData：密码库中读取的密码
  * @param  len：要比对的密码长度
  * 
  * @return 密码匹配返回SUCCESS, 否则返回ERROR
  */
static ErrorStatus Users_PwdCmp(uint8_t *pData, NvPassword_stu_t *pwdData, uint8_t len)
{
	uint8_t pwdLen;
	uint8_t maxLen, *pMaxBuf;
	uint8_t minLen, *pMinBuf;

	pwdLen = Users_GetKeysLen(pwdData->pwd, PWD_LEN_MAX);
	if (pwdLen >= len)
	{
		maxLen = pwdLen;
		pMaxBuf = pwdData->pwd;
		minLen = len;
		pMinBuf = pData;
	}
	else
	{
		minLen = pwdLen;
		pMinBuf = pwdData->pwd;
		maxLen = len;
		pMaxBuf = pData;
	}
	if (Users_MemoryCmp(pMinBuf, minLen, pMaxBuf, maxLen, 1) == SUCCESS)
	{
		return SUCCESS;
	}
	return ERROR;
}

/**
  * @brief  密码“已存在”检查
  * @note   添加新密码时用到
  *         只要新密码包含了密码库中的某个密码，
  *         或者密码库中的某个密码包含了新密码，都认为是已存在
  *
  * @param  pData：新添加的密码数据
  * @param  len：密码长度
  * 
  * @return 密码已存在返回SUCCESS, 不存在返回flase
  */
static ErrorStatus Users_PwdExistsCheck(uint8_t *pData, uint8_t len)
{
	uint8_t id;

	for (id = 0; id < KEYS_QTY_PWD; id++)
	{
		if (gUsersParam.pwd_map[id / 8] & (1 << (id % 8)))
		{
			/* 密码库 */
			NvPassword_stu_t pwdData = {0};
			Users_ReadKeys(USERS_TYPE_PWD, id, &pwdData);
			if (Users_PwdCmp(pData, &pwdData, len) == SUCCESS)
			{
				return SUCCESS;
			}
		}
	}

#if !defined(DXTC_NO_MENU)
	if (id == KEYS_QTY_PWD)
	{
		uint8_t pwdLen;
		/* 管理员密码 */
		pwdLen = Users_GetKeysLen(gUsersParam.admin_pwd, PWD_LEN_MAX);
		if(pwdLen > len)
		{
			if (Users_MemoryCmp(pData, len, gUsersParam.admin_pwd, pwdLen, 1) == SUCCESS)
			{
				return SUCCESS;
			}
		}
		else
		{
			if (Users_MemoryCmp(gUsersParam.admin_pwd, pwdLen, pData, len, 1) == SUCCESS)
			{
				return SUCCESS;
			}
		}
	}
#endif
	return ERROR;
}

/**
  * @brief  统计密码库里面，“永久钥匙”和“胁迫钥匙”的个数
  * @note   keysNum这个编号不统计
  *
  * @param	keysType：秘钥类型
  * @param  keysNum：不统计的密码编号
  * 
  * @return 返回数量
  */
static uint8_t Users_ReadForeverKeysQty(uint8_t keysType, uint8_t keysNum)
{
	uint32_t addr, size, len, qty = 0;
	uint8_t *buffer = NULL, *map = NULL;
	NvPassword_stu_t *pwdData = NULL;
	NvFpt_stu_t *fptData = NULL;
	NvCard_stu_t *cardData = NULL;
	NvFace_stu_t *faceData = NULL;
#if defined(FINGERVEIN_SUPPORT)
	NvFvn_stu_t *fvnData = NULL;
#endif
#if defined(PVN_SUPPORT)
	NvPvn_stu_t *pvnData = NULL;
#endif
#if defined(EVIDENCE_SUPPORT)
	NvEvidence_stu_t *evidenceData = NULL;
#endif

	len = Users_GetKeysQty(keysType);
	map = Users_GetKeysMap(keysType);
	addr = Users_GetKeysDataAddr(keysType);
	size = Users_GetKeysDataSize(keysType);

	buffer = (uint8_t *)OSAL_Malloc(size);
	if (buffer == NULL)
	{
		return 0;
	}

	OSAL_NvRead(addr, buffer, size);
	pwdData = (NvPassword_stu_t *)buffer;
	fptData = (NvFpt_stu_t *)buffer;
	cardData = (NvCard_stu_t *)buffer;
	faceData = (NvFace_stu_t *)buffer;
#if defined(FINGERVEIN_SUPPORT)
	fvnData = (NvFvn_stu_t *)buffer;
#endif
#if defined(PVN_SUPPORT)
	pvnData = (NvPvn_stu_t *)buffer;
#endif
#if defined(EVIDENCE_SUPPORT)
	evidenceData = (NvEvidence_stu_t *)buffer;
#endif
	for (int i = 0; i < len; i++)
	{
		if ((i != keysNum) && (map[i / 8] & (1 << (i % 8))))
		{
			switch (keysType)
			{
				case USERS_TYPE_PWD:
					qty = (pwdData[i].attr == USERS_ATTR_FOREVER || pwdData[i].attr == USERS_ATTR_URGENT) ? qty + 1 : qty;
					break;
				case USERS_TYPE_FPT:
					qty = (fptData[i].attr == USERS_ATTR_FOREVER || fptData[i].attr == USERS_ATTR_URGENT || fptData[i].attr == USERS_ATTR_ADMIN) ? qty + 1 : qty;
					break;
				case USERS_TYPE_CARD:
					qty = (cardData[i].attr == USERS_ATTR_FOREVER || cardData[i].attr == USERS_ATTR_URGENT) ? qty + 1 : qty;
					break;
				case USERS_TYPE_FACE:
					qty = (faceData[i].attr == USERS_ATTR_FOREVER || faceData[i].attr == USERS_ATTR_URGENT) ? qty + 1 : qty;
					break;
			#if defined(FINGERVEIN_SUPPORT)
				case USERS_TYPE_FVN:
					qty = (fvnData[i].attr == USERS_ATTR_FOREVER || fvnData[i].attr == USERS_ATTR_URGENT || fvnData[i].attr == USERS_ATTR_ADMIN) ? qty + 1 : qty;
					break;
			#endif
			#if defined(PVN_SUPPORT)
				case USERS_TYPE_PVN:
					qty = (pvnData[i].attr == USERS_ATTR_FOREVER || pvnData[i].attr == USERS_ATTR_URGENT || pvnData[i].attr == USERS_ATTR_ADMIN) ? qty + 1 : qty;
					break;
			#endif
			#if defined(EVIDENCE_SUPPORT)
				case USERS_TYPE_EVIDENCE:
					qty = (evidenceData[i].attr == USERS_ATTR_FOREVER || evidenceData[i].attr == USERS_ATTR_URGENT || evidenceData[i].attr == USERS_ATTR_ADMIN) ? qty + 1 : qty;
					break;
			#endif
			}
		}
	}
	OSAL_Free(buffer);
	USERS_LOG("Forever keys qty:%d,  keysType:%d, keysNum:%d\r\n", qty, keysType, keysNum);
	return qty;
}

/**
  * @brief  读取某个密钥编号的状态
  * @note
  *
  * @param  keysType：密钥类型
  * @param  keysNum： 密钥编号
  * 
  * @return 返回状态值
  *         USERS_NUMBER_ERROR    错误编号
  *         USERS_NUMBER_EXISTED  编号已占用
  *         USERS_NUMBER_IDLE     编号空闲
  */
static uint8_t Users_ReadKeysNumStatus(uint8_t keysType, uint8_t keysNum)
{
	if ((keysType == USERS_TYPE_PWD && keysNum >= KEYS_QTY_PWD)
		|| (keysType == USERS_TYPE_FPT && keysNum >= KEYS_QTY_FPT)
		|| (keysType == USERS_TYPE_CARD && keysNum >= KEYS_QTY_CARD)
		|| (keysType == USERS_TYPE_FACE && keysNum >= KEYS_QTY_FACE)
#if defined(FINGERVEIN_SUPPORT)
		|| (keysType == USERS_TYPE_FVN && keysNum >= KEYS_QTY_FVN)
#endif
#if defined(PVN_SUPPORT)
		|| (keysType == USERS_TYPE_PVN && keysNum >= KEYS_QTY_PVN)
#endif
#if defined(EVIDENCE_SUPPORT)
		|| (keysType == USERS_TYPE_EVIDENCE && keysNum >= KEYS_QTY_EVIDENCE)
#endif
		)
	{
		return USERS_NUMBER_ERROR;
	}

	if (Users_FindKeys(keysType, keysNum) != SUCCESS)
	{
		return USERS_NUMBER_EXISTED;
	}
	return USERS_NUMBER_IDLE;
}

/**
  * @brief  判断门锁是否激活
  *
  * @param  code：数据指针
  * 
  * @return 成功返回SUCCESS, 失败返回ERROR
  */
static ErrorStatus Users_IsLockActived(uint8_t *code)
{
	// uint8_t activeCode[21] = {0};
	// if (code == NULL)
	// {
	// 	code = activeCode;
	// }
	// if (Users_ReadActivationCode(code) != ERROR) //已烧录激活码
	// {
	// 	if (code[20] == 0) //未激活状态
	// 	{
	// 		return ERROR;
	// 	}
	// }
	return SUCCESS;
}


#if defined(DXTC_NO_MENU)
//验证离线密码
bool OfflinePwd_Verify(uint8_t *input_pwd, uint8_t input_len)
{
    bool res = false;
	uint32_t T, H;
	uint32_t timestamp = 0;
	uint8_t index = 0;
	uint8_t buf[32] = {0};//保存SHA256结果
	uint8_t pwdFacotr[80] = {0};
	uint8_t string[80] = {0};
    
	if (input_len != OFFLINE_PWD_LEN)
	{
		return false;
	}

	/* eSN */
	memcpy(&pwdFacotr[1], gUsersParam.offlinePwd.bleSN, 13);
	
	/* 随机数 */
	for (int k = 0; k < OFFLINE_PWD_RANDOM_LEN; k++)
	{
		sprintf((char*)&pwdFacotr[1+13+2*k], "%02X", gUsersParam.offlinePwd.random[k]);
	}

	//当前时间戳
	OSAL_TimeGet(&timestamp, T_UTC);
	USERS_LOG("timestamp = %d\r\n", timestamp);

	for (int k = 0; k < OFFLINE_PWD_QTY; k++)
	{
		index = k % (OFFLINE_PWD_QTY / 2);
		T = timestamp / (15 * 60) - (k / (OFFLINE_PWD_QTY / 2));

		/* 过滤失效的密钥索引 */
		uint8_t invalid_flag = 0;
		for (int i = 0; i < 2; i++)
		{
			if (T == gUsersParam.offlinePwd.invalid_pwd[i].timestamp)
			{
				if (gUsersParam.offlinePwd.invalid_pwd[i].index & (1 << index))
				{
					invalid_flag = 1;
					break;
				}
			}
		}
		if (invalid_flag)
		{
			continue;
		}

		pwdFacotr[0] = index + '0';
		sprintf((char*)&pwdFacotr[1+13+2*OFFLINE_PWD_RANDOM_LEN], "%d", T);
		USERS_LOG("Offline Pwd Factor: %s\r\n", pwdFacotr);

		// sha256(index+eSN+随机数+T)
		if (Device_Crypto(CALC_SHA256, pwdFacotr, strlen((char *)pwdFacotr), buf, NULL) != 0)
		{
			__USERS_LOG("SHA256 error !\r\n");
			return false;
		}
		for (int j=0; j<32; j++)
		{
			sprintf((char*)&string[j*2], "%02X", buf[j]);
		}
		USERS_LOG("OPF SHA256: %s\r\n", string);

        // 取低4字节
		H = *(uint32_t *)buf;
		USERS_LOG("Int Value: %08X\r\n", H);

		// 取余10e6 生成离线密码
		H %= 1000000;

		// 转换成密码序列保存
		buf[0] = H/100000;
		buf[1] = (H%100000)/10000;
		buf[2] = (H%10000)/1000;
		buf[3] = (H%1000)/100;
		buf[4] = (H%100)/10;
		buf[5] = H%10;
        memset(string, 0, 10);
		for (int j=0; j<6; j++)
		{
			string[j] = buf[j] + '0';
		}
		USERS_LOG("Offline PWD %02d: %s\r\n", k, string);

        // 与输入的密码比对
		if (memcmp(buf, input_pwd, input_len) == 0)
		{
            USERS_LOG("Offline pwd verify success, T: %d, index: %d\r\n", T, index);
			res = true;
			/* 标记该密钥无效 */
			for (int i = 0; i < 2; i++)
			{
				if (T == gUsersParam.offlinePwd.invalid_pwd[i].timestamp) //当前刻度使用过
				{
					USERS_LOG("save invalid pwd\r\n");
					gUsersParam.offlinePwd.invalid_pwd[i].index |= (1 << index);
					break;
				}
				else if (i == 1) //该刻度没被使用过
				{
					for (int j = 0; j < 2; j++)
					{
						if (gUsersParam.offlinePwd.invalid_pwd[j].timestamp != (timestamp / (15 * 60) - 1) && \
							gUsersParam.offlinePwd.invalid_pwd[j].timestamp != (timestamp / (15 * 60))) //查找空闲的刻度
						{
							USERS_LOG("save invalid pwd\r\n");
							gUsersParam.offlinePwd.invalid_pwd[j].timestamp = T;
							gUsersParam.offlinePwd.invalid_pwd[j].index = (1 << index);
							break;
						}
					}
				}
			}
			/* 保存失效的密钥信息 */
			OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam), &gUsersParam, sizeof(gUsersParam));
			break;
		}
	}
	return res;
}
#else
//验证离线密码
bool OfflinePwd_Verify(uint8_t *input_pwd, uint8_t input_len)
{
    bool res = false;
	uint32_t T, H;
	uint32_t timestamp = 0;
	uint8_t buf[32] = {0};//保存SHA256结果
	uint8_t pwdFacotr[80] = {0};
    uint8_t random[OFFLINE_PWD_RANDOM_LEN] = {0};
    

	if (input_len != OFFLINE_PWD_LEN)
	{
		return false;
	}

	//eSN (蓝牙SN)
	memcpy(pwdFacotr, gUsersParam.offlinePwd.bleSN, 13);
	
	//随机数	
	Users_ReadOfflinePwdRandom(random, OFFLINE_PWD_RANDOM_LEN);
	
	//USERS_LOG("random = ");
	for (int k=0; k<OFFLINE_PWD_RANDOM_LEN; k++)
	{
		sprintf((char*)&pwdFacotr[13+2*k], "%02X", random[k]);
	}

	//生成时间段
	OSAL_TimeGet(&timestamp, T_UTC);

	USERS_LOG("timestamp = %d\r\n", timestamp);
	T = timestamp / (5*60) - 6; //当前时刻向前30分钟，向后10分钟内离线密码有效

	for (int k=0; k<OFFLINE_PWD_QTY; k++)
	{
        uint8_t string[80] = {0};

		sprintf((char*)&pwdFacotr[13+2*OFFLINE_PWD_RANDOM_LEN], "%d", T+k);
		USERS_LOG("Offline Pwd Factor: %s\r\n", pwdFacotr);

		// 计算(eSN+随机数+时间戳) SHA256哈希值
		uint32_t pwdFacotrLen = strlen((char *)pwdFacotr);
        if(pwdFacotrLen == 0)
        {
            return false;
        }
		if (Device_Crypto(CALC_SHA256, pwdFacotr, strlen((char *)pwdFacotr), buf, NULL) != 0)
		{
			__USERS_LOG("SHA256 error !\r\n");
			return false;
		}
		for (int j=0; j<32; j++)
		{
			sprintf((char*)&string[j*2], "%02X", buf[j]);
		}
		USERS_LOG("OPF SHA256: %s\r\n", string);

        // 取低4字节
		H = *(uint32_t *)buf;
		__USERS_LOG("Int Value: %08X\r\n", H);

		// 取余10e6 生成离线密码
		H %= 1000000;
		USERS_LOG("Offline PWD: %06d\r\n", H);

		// 转换成密码序列保存
		buf[0] = H/100000;
		buf[1] = (H%100000)/10000;
		buf[2] = (H%10000)/1000;
		buf[3] = (H%1000)/100;
		buf[4] = (H%100)/10;
		buf[5] = H%10;
        memset(string, 0, 10);
		for (int j=0; j<6; j++)
		{
			string[j] = buf[j] + '0';
		}
		USERS_LOG("Offline PWD %02d: %s\r\n", k, string);

        // 与输入的密码比对
		if (memcmp(buf, input_pwd, input_len) == 0)
		{
            USERS_LOG("\033[1;7m" "Offline pwm verify success\r\n");
			res = true;
		}
	}
	return res;
}
#endif

static char* _toLower(char *data)
{
	int len = strlen(data);
	for (int i = 0; i < len; i++)
	{
		if(data[i] >= 'A' && data[i] <= 'Z')
		{
			data[i] += 0x20;
		}
	}
	return data;
}

/**
  * @brief  验证离线密钥 - sha256是否匹配
  * @note   str_pwd_sha256和当前临时密码对比. 
  *
  * @param  str_pwd_sha256：临时密码的SHA256字符串
  * @param  timestamp：当前sha256的时间戳
  * @return 命令执行结果 true / false
  */
ErrorStatus Users_OfflinePwdVerifySha256(char *str_pwd_sha256, uint32_t timestamp)
{
    ErrorStatus res = ERROR;
    uint8_t buf[32] = {0}; //保存SHA256结果
    uint8_t pwdFacotr[80] = {0};
    uint8_t random[28 + 4] = {0};

    if (str_pwd_sha256 == NULL || strlen(str_pwd_sha256) != 64)
        return ERROR;

    //eSN (蓝牙SN)
    memcpy(pwdFacotr, gUsersParam.offlinePwd.bleSN, 13);

    //随机数
    Users_ReadOfflinePwdRandom(random, OFFLINE_PWD_RANDOM_LEN);
    for (int k=0; k<OFFLINE_PWD_RANDOM_LEN; k++)
	{
		sprintf((char*)&pwdFacotr[13+2*k], "%02X", random[k]);
	}

    // 利用 timestamp 生成密钥
    uint8_t string[80] = {0};

    uint32_t T = timestamp / (5 * 60);

    sprintf((char*)&pwdFacotr[13 + 2 * OFFLINE_PWD_RANDOM_LEN], "%d", T);

    // 2. 计算(eSN+随机数+时间戳) SHA256哈希值
	if (Device_Crypto(CALC_SHA256, pwdFacotr, strlen((char *)pwdFacotr), buf, NULL) != 0)
    {
        USERS_LOG("SHA256 error !\r\n");
        return ERROR;
    }
    for (int j = 0; j < 32; j++)
    {
        sprintf((char *)&string[j * 2], "%02x", buf[j]);
    }

    // 3. 与下发密码hash比对: 64字节的字符串
	_toLower(str_pwd_sha256);
    if (memcmp(str_pwd_sha256, string, 64) == 0)
    {
        USERS_LOG("Offline network verify success\r\n");
        res = SUCCESS;
    }

    return res;
}

/**
  * @brief  验证密码
  * @note
  *
  * @param  pData：数据指针
  * @param  len：数据长度
  * @param  dualFlag：双重验证标志，0第一次验证，1第二次验证
  * @param  pRecord：开锁记录数据
  * @param  asterisk：*键输入次数
  * 
  * @return 验证结果
  */
static int32_t Users_VerifyPassword(uint8_t *pData, uint8_t len, uint8_t dualFlag, uint8_t asterisk, int16_t time_zone)
{
	uint8_t activeCode[21] = {0};
	/* 处理激活码逻辑 */
	if (Users_IsLockActived(activeCode) == ERROR) //未激活状态
	{
        uint8_t inpupt_data[6];
		uint8_t digest[20] = {0};

        if (len != 6)
        {
            return NOT_ACTIVATION;
        }

        for (int i=0; i<6; i++)
        {
            inpupt_data[i] = pData[i] + '0';
        }
		OSAL_Crypto(CALC_SHA1, inpupt_data, 6, digest, NULL);

		if (memcmp(activeCode, digest, 20) == 0)
		{
			gUsersParam.activeCodeHash[20] = 1; //设置激活标志
			OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam.activeCodeHash), &gUsersParam.activeCodeHash, sizeof(gUsersParam.activeCodeHash));
			return ACTIVATION_OK; //激活成功
		}
		else
		{
			return NOT_ACTIVATION;
		}
	}

	/* 验证离线密码 */
	if (!gUsersParam.dual_verify)//没有打开安全模式
    {
		if (OfflinePwd_Verify(pData, len) == SUCCESS)
        {
			return USERS_ID_OFFLINE;
        }
    }

	/* 验证密码 */
	uint8_t keysNum, pwdLen;
	FlagStatus urgentFlag = RESET;	//胁迫密码标志位
	NvPassword_stu_t keys_data;
#if !defined(DXTC_NO_MENU)
	pwdLen = Users_GetKeysLen(gUsersParam.admin_pwd, PWD_LEN_MAX);
    USERS_LOG("admin :%d,%d,%d,%d,%d,%d,%d,%d\r\n",gUsersParam.admin_pwd[0],gUsersParam.admin_pwd[1],gUsersParam.admin_pwd[2],gUsersParam.admin_pwd[3],
                                                   gUsersParam.admin_pwd[4],gUsersParam.admin_pwd[5],gUsersParam.admin_pwd[6],gUsersParam.admin_pwd[7]);
	if (Users_MemoryCmp(gUsersParam.admin_pwd, pwdLen, pData, len, 1) == SUCCESS) //验证管理密码
	{
		keysNum = USERS_ID_ADMIN;
		keys_data.attr = USERS_ATTR_ADMIN;
	}
	else
#endif
	{
		keysNum = Users_MatchKeysLibrary(USERS_TYPE_PWD, pData, len, 1, &keys_data); //比对密码库
		if (keysNum >= KEYS_QTY_PWD)
		{
			return VERIFY_ERROR;
		}
	}
	/* 密码比对成功，验证属性 */
	if (keys_data.attr == USERS_ATTR_ADMIN && asterisk >= 2)
	{
		/* 若胁迫功能打开,则需要校验是否为胁迫密码 */
		if(gUsersParam.urgentFlag)
		{
			urgentFlag = Users_UrgentVerify(USERS_TYPE_PWD, keysNum, pData, len);
			if(urgentFlag)
			{
				/* 紧急（胁迫）用户开锁，发消息给应用层 */
				UsersMsg_t usersmsg;
				usersmsg.ID = USERS_MSG_ID_URGENT;
				usersmsg.keysNum = keysNum;
				OSAL_MessagePublish(&usersmsg, sizeof(usersmsg));
			}
		}
		/* 管理员验证成功（管理员属性） */
		return USERS_ID_ADMIN;
	}
	else if (Users_CheckOpenLockKeysAttr(keys_data.attr, USERS_TYPE_PWD, keysNum, time_zone) == SUCCESS)
	{
		#ifdef MI_PID_INFO
		//米家锁 双重验证模式下  只有管理员属性和永久属性参与组合计算； 周期密码不算
		if (gUsersParam.dual_verify && keys_data.attr != USERS_ATTR_FOREVER && keys_data.attr != USERS_ATTR_ADMIN)
		{
			return VERIFY_ERROR;
		}
		#endif 
		/* 属性验证成功 */
		if (dualFlag == 0)
		{
			g_first_verify_keys_type = USERS_TYPE_PWD;
			if (gUsersParam.dual_verify)//打开了安全模式
			{
				return keysNum + VERIFY_DUAL_OFFSET;
			}
		}
		else if (dualFlag == 1)
		{
			if (g_first_verify_keys_type == USERS_TYPE_PWD)
			{
				return keysNum + VERIFY_DUAL_OFFSET; //安全模式下，第一次也是密码认证，返回失败
			}
		}
		/* 若胁迫功能打开,则需要校验是否为胁迫密码 */
		if(gUsersParam.urgentFlag)
		{
			urgentFlag = Users_UrgentVerify(USERS_TYPE_PWD, keysNum, pData, len);
			if(urgentFlag)
			{
				/* 紧急（胁迫）用户开锁，发消息给应用层 */
				UsersMsg_t usersmsg;
				usersmsg.ID = USERS_MSG_ID_URGENT;
				usersmsg.keysNum = keysNum;
				OSAL_MessagePublish(&usersmsg, sizeof(usersmsg));
			}
		}
		return keysNum;//验证成功返回密匙ID
	}
	return VERIFY_ERROR;
}

/**
  * @brief  验证指纹
  * @note
  * 
  * @param  pData：数据指针
  * @param  len：数据长度
  * @param  dualFlag：双重验证标志，0第一次验证，1第二次验证
  * @param  pRecord：开锁记录数据
  * @param  asterisk：*键输入次数
  *
  * @return 返回验证结果
  */
static int32_t Users_VerifyFingerprint(uint8_t *pData, uint8_t len, uint8_t dualFlag, uint8_t asterisk, int16_t time_zone)
{
	/* 处理激活码逻辑 */
	if (Users_IsLockActived(NULL) == ERROR) //未激活状态
	{
		return NOT_ACTIVATION;
	}

	/* 输入的指纹与指纹库比对 */
	NvFpt_stu_t keys_data;
	uint8_t keysNum = Users_MatchKeysLibrary(USERS_TYPE_FPT, pData, len, 0, &keys_data);
	if (keysNum >= KEYS_QTY_FPT)
	{
		return VERIFY_ERROR;
	}

	/* 指纹比对成功，验证属性 */
	if (Users_CheckOpenLockKeysAttr(keys_data.attr, USERS_TYPE_FPT, keysNum, time_zone) == SUCCESS)
	{
		if (USERS_ATTR_ADMIN == keys_data.attr && asterisk >= 2)
		{
			return USERS_ID_ADMIN; //管理员指纹验证成功
		}

		if (dualFlag == 0)
		{
			g_first_verify_keys_type = USERS_TYPE_FPT;
			if (gUsersParam.dual_verify)//打开了安全模式
			{
				return keysNum + VERIFY_DUAL_OFFSET;
			}
		}
		else if (dualFlag == 1)
		{
			if (g_first_verify_keys_type == USERS_TYPE_FPT)
			{
				return keysNum + VERIFY_DUAL_OFFSET; //安全模式下，第一次也是指纹认证，返回失败
			}
		}
		return keysNum;//验证成功返回密匙ID
	}
	return VERIFY_ERROR;
}

#if defined(FINGERVEIN_SUPPORT)
/**
  * @brief  验证指静脉
  * @note
  * 
  * @param  pData：数据指针
  * @param  len：数据长度
  * @param  dualFlag：双重验证标志，0第一次验证，1第二次验证
  * @param  pRecord：开锁记录数据
  * @param  asterisk：*键输入次数
  *
  * @return 返回验证结果
  */
static int32_t Users_VerifyFingervein(uint8_t *pData, uint8_t len, uint8_t dualFlag, uint8_t asterisk, int16_t time_zone)
{
	/* 处理激活码逻辑 */
	if (Users_IsLockActived(NULL) == ERROR) //未激活状态
	{
		return NOT_ACTIVATION;
	}

	/* 输入的指静脉与指静脉库比对 */
	NvFvn_stu_t keys_data;
	uint8_t keysNum = Users_MatchKeysLibrary(USERS_TYPE_FVN, pData, len, 0, &keys_data);
	if (keysNum >= KEYS_QTY_FVN)
	{
		return VERIFY_ERROR;
	}

	/* 指静脉比对成功，验证属性 */
	if (Users_CheckOpenLockKeysAttr(keys_data.attr, USERS_TYPE_FVN, keysNum, time_zone) == SUCCESS)
	{
    if (USERS_ATTR_ADMIN == keys_data.attr && asterisk >= 2)
		{
			return USERS_ID_ADMIN; //管理员指静脉验证成功
		}
        if( keysNum == 0 )
            keysNum = USERS_ID_ADMIN;
		if (dualFlag == 0)
		{
			g_first_verify_keys_type = USERS_TYPE_FVN;
			if (gUsersParam.dual_verify)//打开了安全模式
			{
				return keysNum + VERIFY_DUAL_OFFSET;
			}
		}
		else if (dualFlag == 1)
		{
			if (g_first_verify_keys_type == USERS_TYPE_FVN)
			{
				return keysNum + VERIFY_DUAL_OFFSET; //安全模式下，第一次也是指静脉认证，返回失败
			}
		}
		return keysNum;//验证成功返回密匙ID
	}
	return VERIFY_ERROR;
}
#endif

#if defined(PVN_SUPPORT)
/**
  * @brief  验证掌静脉
  * @note
  * 
  * @param  pData：数据指针
  * @param  len：数据长度
  * @param  dualFlag：双重验证标志，0第一次验证，1第二次验证
  * @param  pRecord：开锁记录数据
  * @param  asterisk：*键输入次数
  *
  * @return 返回验证结果
  */
static int32_t Users_VerifyPvn(uint8_t *pData, uint8_t len, uint8_t dualFlag, uint8_t asterisk, int16_t time_zone)
{
	/* 处理激活码逻辑 */
	if (Users_IsLockActived(NULL) == ERROR) //未激活状态
	{
		return NOT_ACTIVATION;
	}

	/* 输入的指静脉与指静脉库比对 */
	NvPvn_stu_t keys_data;
	uint8_t keysNum = Users_MatchKeysLibrary(USERS_TYPE_PVN, pData, len, 0, &keys_data);
	if (keysNum >= KEYS_QTY_PVN)
	{
		return VERIFY_ERROR;
	}

	/* 指静脉比对成功，验证属性 */
	if (Users_CheckOpenLockKeysAttr(keys_data.attr, USERS_TYPE_PVN, keysNum, time_zone) == SUCCESS)
	{
    if (USERS_ATTR_ADMIN == keys_data.attr && asterisk >= 2)
		{
			return USERS_ID_ADMIN; //管理员指静脉验证成功
		}
        if( keysNum == 0 )
            keysNum = USERS_ID_ADMIN;
		if (dualFlag == 0)
		{
			g_first_verify_keys_type = USERS_TYPE_PVN;
			if (gUsersParam.dual_verify)//打开了安全模式
			{
				return keysNum + VERIFY_DUAL_OFFSET;
			}
		}
		else if (dualFlag == 1)
		{
			if (g_first_verify_keys_type == USERS_TYPE_PVN)
			{
				return keysNum + VERIFY_DUAL_OFFSET; //安全模式下，第一次也是指静脉认证，返回失败
			}
		}
		return keysNum;//验证成功返回密匙ID
	}
	return VERIFY_ERROR;
}
#endif

#if defined(EVIDENCE_SUPPORT)
/**
  * @brief  验证凭证
  * @note
  * 
  * @param  pData：数据指针
  * @param  len：数据长度
  * @param  dualFlag：双重验证标志，0第一次验证，1第二次验证
  * @param  pRecord：开锁记录数据
  * @param  asterisk：0：不用校验时间， 1：需要校验时间 （开锁测试时，只校验凭证，不校验时间）
  *
  * @return 返回验证结果
  */
static int32_t Users_VerifyEvidence(uint8_t *pData, uint8_t len, uint8_t dualFlag, uint8_t asterisk, int16_t time_zone)
{
	/* 输入的凭证与凭证库比对 */
	NvEvidence_stu_t keys_data;
	uint8_t keysNum = Users_MatchKeysLibrary(USERS_TYPE_EVIDENCE, pData, len, 0, &keys_data);

	if(keysNum == USERS_ID_RFEEZE)
	{
		return USERS_ID_RFEEZE;//凭证已冻结
	}
	if (keysNum >= KEYS_QTY_EVIDENCE)
	{
		return 0x06;//凭证不存在
	}

	if(asterisk == 1)
	{
		/* 凭证比对成功，验证属性 */
		if (Users_CheckOpenLockKeysAttr(keys_data.attr, USERS_TYPE_EVIDENCE, keysNum, time_zone) == SUCCESS)
		{
			return 0x00;//验证成功
		}
		else
		{
			return 0x0f;//凭证过期
		}
		return 0x01;//失败
	}
	else//在厂测过程中验证开锁，不校验时间，因为此时时间未校准
	{
		if(keysNum < KEYS_QTY_EVIDENCE)
		{
			return 0x00;
		}
	}
}
#endif

/**
  * @brief  验证卡片
  * @note
  *
  * @param  pData：数据指针
  * @param  len：数据长度
  * @param  dualFlag：双重验证标志，0第一次验证，1第二次验证
  * @param  pRecord：开锁记录数据
  * 
  * @return 验证结果
  */
static int32_t Users_VerifyCard(uint8_t *pData, uint8_t len, uint8_t dualFlag, int16_t time_zone)
{
	/* 处理激活码逻辑 */
	if (Users_IsLockActived(NULL) == ERROR) //未激活状态
	{
		return NOT_ACTIVATION;
	}

	if (len != 4 && len != 7 && len != 10)
	{
		return VERIFY_ERROR; //非法卡片
	}

	USERS_LOG("Verify card: %02x %02x %02x %02x\r\n", pData[0], pData[1], pData[2], pData[3]);

	/* 输入的卡片ID与卡片库比对 */
	NvCard_stu_t keys_data;
	uint8_t keysNum = Users_MatchKeysLibrary(USERS_TYPE_CARD, pData, CARD_LEN_MAX, 0, &keys_data);
	if (keysNum >= KEYS_QTY_CARD)
	{
		USERS_LOG("Card not added\r\n");
		return VERIFY_ERROR;
	}

	/* 卡片比对成功，验证属性 */
	if (Users_CheckOpenLockKeysAttr(keys_data.attr, USERS_TYPE_CARD, keysNum, time_zone) == SUCCESS)
	{
		if (dualFlag == 0)
		{
			g_first_verify_keys_type = USERS_TYPE_CARD;
			if (gUsersParam.dual_verify)//打开了安全模式
			{
				return keysNum + VERIFY_DUAL_OFFSET;
			}
		}
		else if (dualFlag == 1)
		{
			if (g_first_verify_keys_type == USERS_TYPE_CARD)
			{
				return keysNum + VERIFY_DUAL_OFFSET; //安全模式下，第一次也是卡片认证，返回失败
			}
		}
		return keysNum;//验证成功返回密匙ID
	}
	USERS_LOG("Keys attr error\r\n");
	return VERIFY_ERROR;
}

/**
  * @brief  验证人脸
  * @note
  * 
  * @param  pData：数据指针
  * @param  len：数据长度
  * @param  dualFlag：双重验证标志，0第一次验证，1第二次验证
  * @param  pRecord：开锁记录数据
  * @param  asterisk：*键输入次数
  *
  * @return 返回验证结果
  */
static int32_t Users_VerifyFace(uint8_t *pData, uint8_t len, uint8_t dualFlag, uint8_t asterisk, int16_t time_zone)
{
	/* 处理激活码逻辑 */
	if (Users_IsLockActived(NULL) == ERROR) //未激活状态
	{
		return NOT_ACTIVATION;
	}

	/* 输入的人脸与人脸库比对 */
	NvFace_stu_t keys_data;
	uint8_t keysNum = Users_MatchKeysLibrary(USERS_TYPE_FACE, pData, len, 0, &keys_data);
	if (keysNum >= KEYS_QTY_FACE)
	{
		return VERIFY_ERROR;
	}

	/* 人脸比对成功，验证属性 */
	if (Users_CheckOpenLockKeysAttr(keys_data.attr, USERS_TYPE_FACE, keysNum, time_zone) == SUCCESS)
	{
		if (dualFlag == 0)
		{
			g_first_verify_keys_type = USERS_TYPE_FACE;
			if (gUsersParam.dual_verify)//打开了安全模式
			{
				return keysNum + VERIFY_DUAL_OFFSET;
			}
		}
		else if (dualFlag == 1)
		{
			if (g_first_verify_keys_type == USERS_TYPE_FACE)
			{
				return keysNum + VERIFY_DUAL_OFFSET; //安全模式下，第一次也是人脸认证，返回失败
			}
		}
		return keysNum;//验证成功返回密匙ID
	}
	return VERIFY_ERROR;
}

/**
  * @brief  处理 添加新密码 和 修改管理员密码
  * @note   keysNum范围0~9，每个编号对应的默认属性：
  *         0~4：永久
  *         5~8：一次性
  *         9：胁迫
  *
  * @param  pData：新添加的密码数据
  * @param  len：密码长度
  * @param  keysNum：密钥编号
  * @param  dualFlag：双验证标志(添加密码需要连续输入2次同样的密码)
  * @param  opt：0添加密码，1修改管理员密码
  * 
  * @return 返回添加、修改结果
  */
static UsersAddRes_enum_t Users_ProcessAddPassword(uint8_t *pData, uint8_t len, uint8_t keysNum, FlagStatus dualFlag, uint8_t opt, uint8_t keysAttr)
{
	static NvPassword_stu_t pwdData = {0};
	static uint8_t pwdLen;

#if !defined(DXTC_NO_MENU)
	if (Users_GetQty(USERS_TYPE_PWD, 1) == KEYS_QTY_PWD)
	{
		if (opt == 0)
			return ADD_ERR_KEYS_LIB_IS_FULL; //修改管理密码不需要判断密码是否满
	}
#endif

	if (dualFlag == RESET)
	{
		/* 检查新密码长度 */
		if (len < PWD_LEN_MIN || len > PWD_LEN_MAX)
		{
			return ADD_ERR_RANGE;
		}

		/* 检查密码是否有效 */
		if (Users_IsValidPassword(pData, len) != SUCCESS)
		{
			return ADD_ERROR;
		}

		/* 检查密码是否太简单 */
		if (Users_PasswordIsEasy(pData, len) == SUCCESS)
		{
			return ADD_ERR_TOO_SIMPLE;
		}

		/* 检查新密码是否与密码库冲突 */
		if (Users_PwdExistsCheck(pData, len) == SUCCESS)
		{
			return ADD_ERR_EXISTS;
		}

		/* 保存第一次输入的密码 */
		memset(pwdData.pwd, 0XFF, PWD_LEN_MAX);
		memcpy(pwdData.pwd, pData, len);
		pwdLen = len;
		return ADD_ONCE_OK;
	}
	else if (dualFlag == SET)
	{
		/* 检查两次输入是否一致 */
		if (Users_MemoryCmp(pwdData.pwd, pwdLen, pData, len, 0) != SUCCESS)
		{
			return ADD_ERR_NOT_SAME;
		}

		if (opt == 0)
		{
			/* 设置新密码的属性，保存密码 */
			if (keysAttr != 0XFF)
			{
				pwdData.attr = keysAttr; //指定属性
			}
			else
			{
				pwdData.attr = USERS_ATTR_FOREVER;
			}
            pwdData.week = 0;
            pwdData.stime =0;
            pwdData.etime =0;
            OSAL_TimeGet(&pwdData.ctime,T_UTC);
			if (Users_SaveKeys(USERS_TYPE_PWD, keysNum, &pwdData) == SUCCESS)
			{
				pwdLen = 0;
				return ADD_SUCCESS;
			}
		}
		else if (opt == 1)
		{
			/* 保存管理员密码 */
			if (Users_ModifyAdminPassword(pwdData.pwd, pwdLen) == SUCCESS)
			{
				pwdLen = 0;
				g_isModifyAdmin =1;
				return ADD_SUCCESS;
			}
		}
	}
	return ADD_ERROR;
}



/**
  * @brief  无线模块修改密码
  * @note
  *
  * @param  pData：密码数据
  * @param  keysNum：密钥编号
  *         0XFF:修改管理员密码， 其它值:修改用户密码
  * @return 返回添加、修改结果
  */
static UsersAddRes_enum_t Users_ModifyPassword(uint8_t *pData, uint8_t keysNum)
{
	NvPassword_stu_t pwdData;
	uint8_t pwdLen;

	/* 检查新密码长度 */
	
	pwdLen = Users_GetKeysLen(pData, PWD_LEN_MAX);
	if (pwdLen < 6 || pwdLen > 12)
	{
		return ADD_ERR_RANGE;
	}
	
	/* 判断密钥是否存在 */
	if (keysNum != 0XFF)
	{
		if (Users_PwdExistsCheck(pData, pwdLen) == SUCCESS)
		{
			return ADD_ERR_EXISTS;
		}
	}

	/* 检查密码是否有效 */
	if (Users_IsValidPassword(pData, pwdLen) != SUCCESS)
	{
		return ADD_ERROR;
	}

	/* 检查密码是否太简单 */
	if ( Users_PasswordIsEasy(pData, pwdLen) == SUCCESS )
	{
		return ADD_ERR_TOO_SIMPLE;
	}

	/* 检查新密码是否与密码库冲突 */
	if ( Users_PwdExistsCheck(pData, pwdLen) == SUCCESS )
	{
		return ADD_ERR_EXISTS;
	}

	if (keysNum == 0XFF)
	{
		/* 保存管理员密码 */
		if (Users_ModifyAdminPassword(pData, pwdLen) == SUCCESS)
		{
			return ADD_SUCCESS;
		}
	}
	else
	{
		/* 保存用户密码 */
		Users_ReadKeys(USERS_TYPE_PWD, keysNum, &pwdData);

		memset(pwdData.pwd, 0XFF, PWD_LEN_MAX);
		memcpy(pwdData.pwd, pData, pwdLen);
		
		if (Users_SaveKeys(USERS_TYPE_PWD, keysNum, &pwdData) == SUCCESS)
		{
			return ADD_SUCCESS;
		}
	}
	return ADD_ERROR;
}



/**
  * @brief  处理添加指纹
  * @note   keysNum范围0~94，默认属性：永久
  *                    95~99 默认属性：胁迫指纹
  * 
  * @param  fingerId：指纹图像ID
  * @param  keysNum：密钥编号
  * 
  * @return 返回添加结果
  */
static UsersAddRes_enum_t Users_ProcessAddFingerprint(uint8_t fingerId, uint8_t keysNum, uint8_t keysAttr)
{
	NvFpt_stu_t fingerData = {0};
	#if !defined(ADMIN_FPT_DISABLE)
	if ((Users_GetQty(USERS_TYPE_FPT, 1) == KEYS_QTY_FPT - 1) && (fingerId != 0))
	#else
	if ((Users_GetQty(USERS_TYPE_FPT, 1) == KEYS_QTY_FPT))
	#endif
	{
		#if !defined(ADMIN_FPT_DISABLE)
		if (fingerId != 0)
		#else
		#endif
        {
			return ADD_ERR_KEYS_LIB_IS_FULL; //指纹库满了还可以修改/添加
        }
	}

	if (fingerId != keysNum)
	{
		return ADD_ERROR;
	}

	if (keysNum == 0) //管理指纹编号固定为0
	{	
		#if defined(ADMIN_FPT_DISABLE)
		if (keysAttr != 0XFF)
		{
			fingerData.attr = keysAttr; //指定属性
		}
		else //未指定，按默认属性设置
		{
			fingerData.attr = USERS_ATTR_FOREVER;
		}
		#else
		fingerData.attr = USERS_ATTR_ADMIN;
		#endif
	}
	else
	{
		if (keysAttr != 0XFF)
		{
			fingerData.attr = keysAttr; //指定属性
		}
		else //未指定，按默认属性设置
		{
			fingerData.attr = USERS_ATTR_FOREVER;
		}
	}

	fingerData.fpt = fingerId;
    fingerData.week = 0;
    fingerData.stime =0;
    fingerData.etime =0;
    OSAL_TimeGet(&fingerData.ctime,T_UTC);
	if (Users_SaveKeys(USERS_TYPE_FPT, keysNum, &fingerData) == SUCCESS)
	{
		return ADD_SUCCESS;
	}
	return ADD_ERROR;
}

#if defined(FINGERVEIN_SUPPORT)
/**
  * @brief  处理添加指静脉
  * @note   keysNum范围0~99，
  * 
  * @param  fingerveinId：指静脉图像ID
  * @param  keysNum：密钥编号
  * 
  * @return 返回添加结果
  */
static UsersAddRes_enum_t Users_ProcessAddFingervein(uint8_t fingerveinId, uint8_t keysNum, uint8_t keysAttr)
{
	NvFvn_stu_t fingerveinData = {0};
	if ((Users_GetQty(USERS_TYPE_FVN, 1) == KEYS_QTY_FVN - 1) && (fingerveinId != 0))
	{
		if (fingerveinId != 0)
        {
			return ADD_ERR_KEYS_LIB_IS_FULL; //添加失败，指静脉库已满
        }
	}

	if (fingerveinId != keysNum)
	{
		return ADD_ERROR;
	}

	if (keysNum == 0) //管理指静脉编号固定为0
	{	
		fingerveinData.attr = USERS_ATTR_ADMIN;
	}
	else
	{
		if (keysAttr != 0XFF)
		{
			fingerveinData.attr = keysAttr; //指定属性
		}
		else //未指定，按默认属性设置
		{
			fingerveinData.attr = USERS_ATTR_FOREVER;
		}
	}

	fingerveinData.fvn = fingerveinId;
    fingerveinData.week = 0;
    fingerveinData.stime =0;
    fingerveinData.etime =0;
    OSAL_TimeGet(&fingerveinData.ctime,T_UTC);
	if (Users_SaveKeys(USERS_TYPE_FVN, keysNum, &fingerveinData) == SUCCESS)
	{
		return ADD_SUCCESS;
	}
	return ADD_ERROR;
}
#endif

#if defined(PVN_SUPPORT)
/**
  * @brief  处理添加掌静脉
  * @note   keysNum范围0~99，
  * 
  * @param  zjmId：指静脉图像ID
  * @param  keysNum：密钥编号
  * 
  * @return 返回添加结果
  */
static UsersAddRes_enum_t Users_ProcessAddPvn(uint8_t pvnID, uint8_t keysNum, uint8_t keysAttr)
{
	NvPvn_stu_t pvnData = {0};
	if ((Users_GetQty(USERS_TYPE_PVN, 1) == KEYS_QTY_PVN - 1) && (pvnID != 0))
	{
		if (pvnID != 0)
        {
			return ADD_ERR_KEYS_LIB_IS_FULL; //添加失败，掌静脉库已满
        }
	}

	if (pvnID != keysNum)
	{
		return ADD_ERROR;
	}

	if (keysNum == 0) //管理指静脉编号固定为0
	{	
		pvnData.attr = USERS_ATTR_ADMIN;
	}
	else
	{
		if (keysAttr != 0XFF)
		{
			pvnData.attr = keysAttr; //指定属性
		}
		else //未指定，按默认属性设置
		{
			pvnData.attr = USERS_ATTR_FOREVER;
		}
	}

	pvnData.pvnID = pvnID;
    pvnData.week = 0;
    pvnData.stime =0;
    pvnData.etime =0;
    OSAL_TimeGet(&pvnData.ctime,T_UTC);
	if (Users_SaveKeys(USERS_TYPE_PVN, keysNum, &pvnData) == SUCCESS)
	{
		return ADD_SUCCESS;
	}
	return ADD_ERROR;
}
#endif

#if defined(EVIDENCE_SUPPORT)
/**
  * @brief  处理添加凭证
  * @note   keysNum范围0~19，
  * 
  * @param  zjmId：凭证ID
  * @param  keysNum：密钥编号
  * 
  * @return 返回添加结果
  */
static UsersAddRes_enum_t Users_ProcessAddEvidence(uint8_t *pData, uint8_t len, uint8_t evidenceID, uint8_t keysNum, uint8_t keysAttr)
{
	NvEvidence_stu_t evidenceData = {0};
	if ((Users_GetQty(USERS_TYPE_EVIDENCE, 1) == KEYS_QTY_EVIDENCE) && (evidenceID != 0))
	{
		if (evidenceID != 0)
        {
			return ADD_ERR_KEYS_LIB_IS_FULL; //添加失败，凭证库已满
        }
	}

	/* 新凭证与凭证库比对，判断是否已添加 */
	if (Users_MatchKeysLibrary(USERS_TYPE_EVIDENCE, &evidenceID, len, 1, &evidenceData) < KEYS_QTY_EVIDENCE)
	{
		return ADD_ERR_EXISTS;
	}

	if (keysNum == 0) //管理指静脉编号固定为0
	{	
		evidenceData.attr = USERS_ATTR_ADMIN;
	}
	else
	{
		if (keysAttr != 0XFF)
		{
			evidenceData.attr = keysAttr; //指定属性
		}
		else //未指定，按默认属性设置
		{
			evidenceData.attr = USERS_ATTR_FOREVER;
		}
	}

	memcpy(evidenceData.Evidence, pData, len);
	evidenceData.EvidenceId = evidenceID;
	evidenceData.EvidenceStatus = 0x02;//0x01:冻结， 0x02启用  ，添加的默认全部启用
    evidenceData.week = 0;
    evidenceData.stime =0;
    evidenceData.etime =0;
    OSAL_TimeGet(&evidenceData.ctime,T_UTC);
	if (Users_SaveKeys(USERS_TYPE_EVIDENCE, keysNum, &evidenceData) == SUCCESS)
	{
		return ADD_SUCCESS;
	}
	return ADD_ERROR;
}
#endif

/**
  * @brief  处理添加卡片
  * @note   keysNum范围0~99，每个编号的默认属性：永久
  *
  * @param  pData：新添加的卡片ID
  * @param  len：ID长度
  * @param  keysNum：密钥编号
  * 
  * @return 返回添加结果
  */
static UsersAddRes_enum_t Users_ProcessAddCard(uint8_t *pData, uint8_t len, uint8_t keysNum, uint8_t keysAttr)
{
	NvCard_stu_t cardData = {0};
	
	if (Users_GetQty(USERS_TYPE_CARD, 1) == KEYS_QTY_CARD)
	{
		return ADD_ERR_KEYS_LIB_IS_FULL;
	}

	if (len != 4 && len != 7 && len != 10)
	{
        #if defined(DXTC_NO_MENU)
        return ADD_ERR_DARD_ILLEGAL; //非法卡片
        #else
		return ADD_ERROR; //非法卡片
        #endif
    }

	/* 新卡与卡片库比对，判断是否已添加 */
	if (Users_MatchKeysLibrary(USERS_TYPE_CARD, pData, len, 0, &cardData) < KEYS_QTY_CARD)
	{
		return ADD_ERR_CARD_EXISTS;
	}

	/* 保存卡片 */
	if (keysAttr != 0XFF)
	{
		cardData.attr = keysAttr; //指定属性
	}
	else //未指定，按默认属性设置
	{
		cardData.attr = USERS_ATTR_FOREVER;
	}
	memcpy(cardData.card, pData, len);
    cardData.week = 0;
    cardData.stime =0;
    cardData.etime =0;
    OSAL_TimeGet(&cardData.ctime,T_UTC);
	if (Users_SaveKeys(USERS_TYPE_CARD, keysNum, &cardData) == SUCCESS)
	{
		return ADD_SUCCESS;
	}
	return ADD_ERROR;
}

/**
  * @brief  处理添加人脸
  * @note   keysNum范围0~94，默认属性：永久
  *                    95~99 默认属性：胁迫指纹
  * 
  * @param  fingerId：指纹图像ID
  * @param  keysNum：密钥编号
  * 
  * @return 返回添加结果
  */
static UsersAddRes_enum_t Users_ProcessAddFace(uint8_t faceId, uint8_t keysNum, uint8_t keysAttr)
{
	NvFace_stu_t faceData = {0};

	if ((Users_GetQty(KEYS_QTY_FACE, 1) == KEYS_QTY_FACE - 1) && (faceId != 0))
	{
		if (faceId != 0)
        {
			return ADD_ERR_KEYS_LIB_IS_FULL; //人脸库满了还可以修改/添加
        }
	}

	if (faceId != keysNum)
	{
		return ADD_ERROR;
	}

	if (keysAttr != 0XFF)
	{
		faceData.attr = keysAttr; //指定属性
	}
	else //未指定，按默认属性设置
	{
		faceData.attr = USERS_ATTR_FOREVER;
	}

	faceData.faceID = faceId;
    faceData.week = 0;
    faceData.stime =0;
    faceData.etime =0;
    OSAL_TimeGet(&faceData.ctime,T_UTC);
	if (Users_SaveKeys(USERS_TYPE_FACE, keysNum, &faceData) == SUCCESS)
	{
		return ADD_SUCCESS;
	}
	return ADD_ERROR;
}


#if defined(FINGERVEIN_SUPPORT)
/**
  * @brief  删除密钥时，核对安全模式，确认是否可以删除
  * @note   执行删除操作前，调用该函数
  *
  * @param  keysType：密钥类型
  * @param  keysNum：密钥编号，0XFF表示要删除所有密钥
  * 
  * @return 返回ERROR，不能删除，为安全模式
  */
static ErrorStatus Users_DelKeysCheckSafeMode(uint8_t keysType, uint8_t keysNum)
{
	uint8_t fptQty, cardQty, faceQty, fvnQty;

	if (gUsersParam.dual_verify)//打开了安全模式
	{
		USERS_LOG("gUsersParam.dual_verify\r\n");
		fptQty = Users_ReadForeverKeysQty(USERS_TYPE_FPT, (keysType == USERS_TYPE_FPT) ? keysNum : 0xff);//所有永久钥匙的数量
        if (Users_FindKeys(USERS_TYPE_FPT, 0) != SUCCESS)
        {
            fptQty++;
        }
		cardQty = Users_ReadForeverKeysQty(USERS_TYPE_CARD, (keysType == USERS_TYPE_CARD) ? keysNum : 0xff);
		faceQty = Users_ReadForeverKeysQty(USERS_TYPE_FACE, (keysType == USERS_TYPE_FACE) ? keysNum : 0xff);
		fvnQty = Users_ReadForeverKeysQty(USERS_TYPE_FVN, (keysType == USERS_TYPE_FVN) ? keysNum : 0xff);
		if (Users_FindKeys(USERS_TYPE_FVN, 0) != SUCCESS)
        {
            fvnQty++;
        }
		if (keysNum == 0XFF)
		{
			if(keysType == USERS_TYPE_FPT)//如果要删除的是所有指纹,需要判断卡片和人脸和指静脉数量是否都为0
			{
				if(cardQty == 0 && faceQty == 0 && fvnQty == 0 && Users_FindKeys(USERS_TYPE_FPT, 0) == SUCCESS)
				{
					return ERROR;
				}
			}
			else if(keysType == USERS_TYPE_CARD)//如果要删除的是所有卡片,需要判断指纹和人脸和指静脉数量是否都为0
			{
				if(fptQty == 0 && faceQty == 0 && fvnQty == 0 )
				{
					return ERROR;
				}
			}
			if(keysType == USERS_TYPE_FACE)//如果要删除的是所有人脸,需要判断指纹和卡片和指静脉数量是否都为0
			{
				if(fptQty == 0 && cardQty == 0 && fvnQty == 0)
				{
					return ERROR;
				}
			}
			if(keysType == USERS_TYPE_FVN)//如果要删除的是所有指静脉,需要判断指纹和卡片和人脸数量是否都为0，
			{
				if(fptQty == 0 && cardQty == 0 && faceQty == 0 && Users_FindKeys(USERS_TYPE_FVN, 0) == SUCCESS)
				{
					return ERROR;
				}
			}
//			if ((keysType == USERS_TYPE_FPT && cardQty == 0 && Users_ReadKeysNumStatus(USERS_TYPE_FPT, 0) == USERS_NUMBER_IDLE) 
//				|| (keysType == USERS_TYPE_CARD && fptQty == 0) )
//			{
//				return ERROR;
//			}
		}
		else
		{
			if (cardQty == 0 && fptQty == 0 && faceQty == 0 && fvnQty == 0)
			{
				return ERROR;
			}
		}
	}
	return SUCCESS;
}
#else
/**
  * @brief  删除密钥时，核对安全模式，确认是否可以删除
  * @note   执行删除操作前，调用该函数
  *
  * @param  keysType：密钥类型
  * @param  keysNum：密钥编号，0XFF表示要删除所有密钥
  * 
  * @return 返回ERROR，不能删除，为安全模式
  */
static ErrorStatus Users_DelKeysCheckSafeMode(uint8_t keysType, uint8_t keysNum)
{
	uint8_t fptQty=0, cardQty=0, faceQty=0,pvnQty=0,evidenceQty;
	if (gUsersParam.dual_verify)//打开了安全模式
	{
		USERS_LOG("gUsersParam.dual_verify\r\n");
		fptQty = Users_ReadForeverKeysQty(USERS_TYPE_FPT, (keysType == USERS_TYPE_FPT) ? keysNum : 0xff);//所有永久钥匙的数量
		if (Users_FindKeys(USERS_TYPE_FPT, 0) != SUCCESS)
        {
            fptQty++;
        }
		cardQty = Users_ReadForeverKeysQty(USERS_TYPE_CARD, (keysType == USERS_TYPE_CARD) ? keysNum : 0xff);
		faceQty = Users_ReadForeverKeysQty(USERS_TYPE_FACE, (keysType == USERS_TYPE_FACE) ? keysNum : 0xff);
		#if defined(PVN_SUPPORT)
		pvnQty = Users_ReadForeverKeysQty(USERS_TYPE_PVN, (keysType == USERS_TYPE_PVN) ? keysNum : 0xff);//所有永久钥匙的数量
        if (Users_FindKeys(USERS_TYPE_PVN, 0) != SUCCESS)
        {
            pvnQty++;
        }
		#endif
		#if defined(EVIDENCE_SUPPORT)
		evidenceQty = Users_ReadForeverKeysQty(USERS_TYPE_EVIDENCE, (keysType == USERS_TYPE_EVIDENCE) ? keysNum : 0xff);//所有永久钥匙的数量
        if (Users_FindKeys(USERS_TYPE_EVIDENCE, 0) != SUCCESS)
        {
            evidenceQty++;
        }
		#endif

		if (keysNum == 0XFF)
		{
			if(keysType == USERS_TYPE_FPT)//如果要删除的是所有指纹,需要判断卡片和人脸数量是否都为0
			{
				if(pvnQty == 0 &&cardQty == 0 && faceQty == 0 && Users_FindKeys(USERS_TYPE_FPT, 0) == SUCCESS)
				{
					return ERROR;
				}
			}
			else if(keysType == USERS_TYPE_CARD)//如果要删除的是所有卡片,需要判断指纹和人脸数量是否都为0
			{
				if(pvnQty == 0 && fptQty == 0 && faceQty == 0)
				{
					return ERROR;
				}
			}
			else if(keysType == USERS_TYPE_FACE)//如果要删除的是所有人脸,需要判断指纹和卡片数量是否都为0
			{
				if(pvnQty == 0 && fptQty == 0 && cardQty == 0)
				{
					return ERROR;
				}
			}
			else if(keysType == USERS_TYPE_PVN)//如果要删除的是所有掌静脉,需要判断指纹和卡片数量是否都为0
			{
				if(faceQty == 0 && fptQty == 0 && cardQty == 0 && Users_FindKeys(USERS_TYPE_PVN, 0) == SUCCESS)
				{
					return ERROR;
				}
			}
			else if(keysType == USERS_TYPE_EVIDENCE)//如果要删除的是所有掌静脉,需要判断指纹和卡片数量是否都为0
			{
				if(faceQty == 0 && fptQty == 0 && cardQty == 0 && Users_FindKeys(USERS_TYPE_EVIDENCE, 0) == SUCCESS)
				{
					return ERROR;
				}
			}
		}
		else
		{
			if (cardQty == 0 && fptQty == 0 && faceQty == 0 && pvnQty == 0 && evidenceQty == 0)
			{
				return ERROR;
			}
		}
	}
	return SUCCESS;
}
#endif   //end defined(FINGERVEIN_SUPPORT)


/**
  * @brief  删除全部密钥
  * @note
  *
  * @param  keysType：密钥类型
  * 
  * @return 删除成功返回SUCCESS
  *         安全模式下，不能删除：返回ERROR
  */
static ErrorStatus Users_ProcessDeleteAllKeys(uint8_t keysType)
{
	USERS_LOG("DeleteAllKeys keysType :%x\r\n", keysType);
	if (Users_DelKeysCheckSafeMode(keysType, 0XFF) == ERROR)
	{
		USERS_LOG("Users_DelKeysCheckSafeMode\r\n");
		return ERROR; //安全模式不能删除
	}
	if (keysType == USERS_TYPE_FPT)
	{
	}
	else if (keysType == 0XFF)
	{
	}
	return Users_DeleteMultiKeys(keysType);
}

/**
  * @brief  处理删除一个密钥
  *
  * @param  keysType：密钥类型
  * @param  keysNum：密钥编号
  *
  * @return 删除成功返回SUCCESS
  *         安全模式下，不能删除：返回ERROR
  */
static ErrorStatus Users_ProcessDeleteOneKeys(uint8_t keysType, uint8_t keysNum)
{
	if (Users_DelKeysCheckSafeMode(keysType, keysNum) == ERROR)
	{
		return ERROR; //安全模式不能删除
	}
	if (keysType == USERS_TYPE_FPT)
	{
		
	}
	return Users_DeleteKeys(keysType, keysNum);
}

/**
  * @brief  判断管理员密码是否太简单
  * @note
  * 
  * @return 简单返回true  复杂返回false
  */
static ErrorStatus Users_AdminPwdIsEasy(void)
{
	uint8_t len = Users_GetKeysLen(gUsersParam.admin_pwd, PWD_LEN_MAX);
	return Users_PasswordIsEasy(gUsersParam.admin_pwd, len);
}

/**
  * @brief  判断密钥库是否满了
  *
  * @param  不带语音以及显示屏操作
  *
  * @return 满了返回SUCCESS，没满返回ERROR
  */
static ErrorStatus Users_AllKeysIsFull(void)
{
	ErrorStatus pwd_status = ERROR, card_status = ERROR, fpt_status = ERROR, face_status = ERROR,zjm_status =ERROR, evidence_status = ERROR;

	if (Users_GetQty(USERS_TYPE_PWD, 1) == KEYS_QTY_PWD)
		pwd_status = SUCCESS; //密钥库已满
	if (Users_GetQty(USERS_TYPE_FPT, 1) == KEYS_QTY_FPT - 1)
		fpt_status = SUCCESS; //指纹库已满
	if (Users_GetQty(USERS_TYPE_CARD, 1) == KEYS_QTY_CARD)
		card_status = SUCCESS; //卡片库已满
	if (Users_GetQty(USERS_TYPE_FACE, 1) == KEYS_QTY_FACE)
		face_status = SUCCESS; //人脸库已满
	#if defined(PVN_SUPPORT)
	if (Users_GetQty(USERS_TYPE_PVN, 1) == KEYS_QTY_PVN)
		zjm_status = SUCCESS; //掌静脉库已满
	if (pwd_status == SUCCESS && fpt_status == SUCCESS && card_status == SUCCESS && face_status == SUCCESS && zjm_status == SUCCESS)
	{
		return SUCCESS;
	}
	#endif
	#if defined(EVIDENCE_SUPPORT)
	if (Users_GetQty(USERS_TYPE_EVIDENCE, 1) == KEYS_QTY_EVIDENCE)
		evidence_status = SUCCESS; //凭证库已满
	if (pwd_status == SUCCESS && fpt_status == SUCCESS && card_status == SUCCESS && face_status == SUCCESS && zjm_status == SUCCESS && evidence_status == SUCCESS)
	{
		return SUCCESS;
	}
	#else
	if (pwd_status == SUCCESS && fpt_status == SUCCESS && card_status == SUCCESS && face_status == SUCCESS)
	{
		return SUCCESS;
	}
	#endif
	return ERROR;
}

/**
  * @brief 所有秘钥类型判断是否为空
  * @note  不带语音播报跟弹框操作
  */
static ErrorStatus Users_AllKeysIsEmpty(void)
{
	ErrorStatus pwd_status = ERROR, card_status = ERROR, fpt_status = ERROR, face_status = ERROR,zjm_status =ERROR,evidence_status = ERROR;

	if (Users_GetQty(USERS_TYPE_PWD, 1) == 0)
		pwd_status = SUCCESS; //密钥库为空
	if (Users_GetQty(USERS_TYPE_FPT, 1) == 0)
		fpt_status = SUCCESS; //指纹库为空
	if (Users_GetQty(USERS_TYPE_CARD, 1) == 0)
		card_status = SUCCESS; //卡片库为空
	if (Users_GetQty(USERS_TYPE_FACE, 1) == 0)
		face_status = SUCCESS; //卡片库为空
	#if defined(PVN_SUPPORT)
	if (Users_GetQty(USERS_TYPE_PVN, 1) == 0)
		zjm_status = SUCCESS; //掌静脉库为空
	if (pwd_status == SUCCESS && fpt_status == SUCCESS && card_status == SUCCESS && face_status == SUCCESS && zjm_status == SUCCESS)
	{
		return SUCCESS;
	}
	#endif
	#if defined(EVIDENCE_SUPPORT)
	if (Users_GetQty(USERS_TYPE_EVIDENCE, 1) == 0)
		evidence_status = SUCCESS; //凭证库为空
	if (pwd_status == SUCCESS && fpt_status == SUCCESS && card_status == SUCCESS && face_status == SUCCESS && zjm_status == SUCCESS && evidence_status == SUCCESS)
	{
		return SUCCESS;
	}
	#else
	if (pwd_status == SUCCESS && fpt_status == SUCCESS && card_status == SUCCESS && face_status == SUCCESS)
	{
		return SUCCESS;
	}
	#endif
	return ERROR;
}

/**
  * @brief  验证用户   
  * @note  
  *  
  * @param  pData：新添加的密钥数据
  * @param  len：密钥长度
  * @param  dualFlag：双验证标志(添加密码需要连续输入2次同样的密码)
  * @param  keysType：密钥类型
  * @param  asterisk：*键输入次数
  * 
  * @return 正常模式验证成功返回：user_id
  *         双重验证模式下首次验证成功返回：user_id + VERIFY_DUAL_OFFSET
  *         验证错误返回负数：见头文件宏定义
  */
static int32_t Users_Verify(uint8_t *pData, uint8_t len, uint8_t dualFlag, uint8_t keysType, uint8_t asterisk, int16_t time_zone)
{
	switch (keysType)
	{
		case USERS_TYPE_PWD:
			return Users_VerifyPassword(pData, len, dualFlag, asterisk, time_zone);

		case USERS_TYPE_FPT:
			return Users_VerifyFingerprint(pData, len, dualFlag, asterisk, time_zone);

		case USERS_TYPE_CARD:
			return Users_VerifyCard(pData, len, dualFlag, time_zone);
		
		case USERS_TYPE_FACE:
			return Users_VerifyFace(pData, len, dualFlag, asterisk, time_zone);

#if defined(FINGERVEIN_SUPPORT)
		case USERS_TYPE_FVN:
			return Users_VerifyFingervein(pData, len, dualFlag, asterisk, time_zone);
#endif
#if defined(PVN_SUPPORT)
		case USERS_TYPE_PVN:
			return Users_VerifyPvn(pData, len, dualFlag, asterisk, time_zone);
#endif
#if defined(EVIDENCE_SUPPORT)
		case USERS_TYPE_EVIDENCE:
			return Users_VerifyEvidence(pData, len, dualFlag, asterisk, time_zone);
#endif
		default:
			return -100;
	}
}

/**
  * @brief  添加用户
  *         
  * @note   
  * 
  * @param  keysType：密钥类型
  * @param  pData：新添加的密钥数据
  * @param  len：密钥长度
  * @param  keysNum：密钥编号
  * @param  dualFlag：双验证标志(添加密码需要连续输入2次同样的密码)
  * 
  * @return 返回用户添加结果
  */
static UsersAddRes_enum_t Users_Add(uint8_t keysType, uint8_t keysNum, uint8_t *pData, uint8_t len, uint8_t keysAttr, FlagStatus dualFlag)
{
	USERS_LOG("keysType: %d, keysNum: %d\r\n", keysType, keysNum);
	switch (keysType)
	{
		case USERS_TYPE_PWD:
			return Users_ProcessAddPassword(pData, len, keysNum, dualFlag, ((keysNum == USERS_ID_ADMIN) ? 1 : 0), keysAttr);

		case USERS_TYPE_FPT:
			return Users_ProcessAddFingerprint(pData[0], keysNum, keysAttr);

		case USERS_TYPE_CARD:
			return Users_ProcessAddCard(pData, len, keysNum, keysAttr);
		
		case USERS_TYPE_FACE:
			return Users_ProcessAddFace(pData[0], keysNum, keysAttr);

#if defined(FINGERVEIN_SUPPORT)
		case USERS_TYPE_FVN:
			return Users_ProcessAddFingervein(pData[0], keysNum, keysAttr);
#endif
#if defined(PVN_SUPPORT)
		case USERS_TYPE_PVN:
			return Users_ProcessAddPvn(pData[0], keysNum, keysAttr);
#endif
#if defined(EVIDENCE_SUPPORT)
		case USERS_TYPE_EVIDENCE:
			return Users_ProcessAddEvidence(&pData[1], len, pData[0], keysNum, keysAttr);
#endif

		default:
			return ADD_ERROR;
	}
}

/**
  * @brief  删除用户(data为NULL时删除全部用户)
  * @note  若编号为0Xff,则按密钥删除,否则按编码删除.若编号为0Xff,密钥数据为NULL,则删除全部用户
  * 
  * @param  keysType：密钥类型
  * @param  keysNum：密钥编号
  * @param  data：密钥数据
  * @param  len：密钥长度
  * 
  * @return 删除成功返回密钥编号,否则返回USERS_DEL_ERR
  */
static int32_t Users_Del(uint8_t keysType, uint8_t keysNum, uint8_t *data, uint8_t len)
{
	USERS_LOG("keysType: %d, keysNum: %d, len: %d\r\n", keysType, keysNum, len);
	if(keysNum != 0xff)	//按编码删除
	{
		if(Users_ProcessDeleteOneKeys(keysType, keysNum) == SUCCESS)
		{
			return keysNum;//删除成功,返回删除的密钥编号
		}
		else
		{
			return USERS_DEL_ERR;
		}
	}
	else//按密钥删除
	{
		if(data == NULL)//删除全部用户
		{
			if(Users_ProcessDeleteAllKeys(keysType) == SUCCESS)
			{
				return 0xFF;
			}
			else
			{
				return USERS_DEL_ERR;
			}
		}
		else//删除指定用户
		{
			uint8_t qty;
			uint8_t *buffer = NULL, *map = NULL;
			uint32_t addr, size;
			NvPassword_stu_t *pwdData = NULL;
			NvFpt_stu_t *fptData = NULL;
			NvCard_stu_t *cardData = NULL;
			NvFace_stu_t *faceData = NULL;
			#if defined(PVN_SUPPORT)
			NvPvn_stu_t *pvnData = NULL;
			#endif
		#if defined(FINGERVEIN_SUPPORT)
			NvFvn_stu_t *fvnData = NULL;
		#endif
			#if defined(EVIDENCE_SUPPORT)
			NvEvidence_stu_t *evidenceData = NULL;
			#endif

			//删除密码时,如果是按密钥删除,输入的长度小于最小长度,直接返回失败
			if(keysType == USERS_TYPE_PWD && keysNum == 0xff && len < PWD_LEN_MIN)
			{
				return USERS_DEL_ERR;
			}
			qty = Users_GetKeysQty(keysType);
			map = Users_GetKeysMap(keysType);
			addr = Users_GetKeysDataAddr(keysType);
			size = Users_GetKeysDataSize(keysType);
			
			buffer = (uint8_t *)OSAL_Malloc(size);
			if (buffer == NULL)
			{
				return USERS_DEL_ERR;
			}
			OSAL_NvRead(addr, buffer, size);
			pwdData = (NvPassword_stu_t *)buffer;
			fptData = (NvFpt_stu_t *)buffer;
			cardData = (NvCard_stu_t *)buffer;
			faceData = (NvFace_stu_t *)buffer;
		#if defined(FINGERVEIN_SUPPORT)
			fvnData = (NvFvn_stu_t *)buffer;
		#endif
		#if defined(PVN_SUPPORT)
			pvnData = (NvPvn_stu_t *)buffer;
		#endif
		#if defined(EVIDENCE_SUPPORT)
			evidenceData = (NvEvidence_stu_t *)buffer;
		#endif

			for (int i = 0; i < qty; i++)
			{
				if (i == 0 && keysType == USERS_TYPE_FPT)
				{
					//管理员指纹不算指纹数量
				}
			#if defined(FINGERVEIN_SUPPORT)
				else if (i == 0 && keysType == USERS_TYPE_FVN)
				{
					//管理员指静脉不算指静脉数量
				}
			#endif
				else if ( map[i / 8] & (1 << (i % 8)) ) //当前用户有效的时候才进行删除秘钥操作
				{
					switch (keysType)
					{
						case USERS_TYPE_PWD:
						{
							uint8_t pwdLen = Users_GetKeysLen(pwdData[i].pwd, PWD_LEN_MAX);
							USERS_LOG("pwdLen:%d, len: %d\r\n", pwdLen, len);	
							if(memcmp(data, pwdData[i].pwd, len) == 0 && (pwdLen == len) )//如果匹配成功,则进行删除
							{
								OSAL_Free(buffer);//提前退出函数要释放内存
								if(Users_ProcessDeleteOneKeys(keysType, i) == SUCCESS)
								{
									return i;
								}
								else
								{
									return USERS_DEL_ERR;
								}
							}
						}
							break;
						case USERS_TYPE_FPT:
							if(memcmp(data, &fptData[i].fpt, len) == 0)//如果匹配成功,则进行删除
							{
								OSAL_Free(buffer);//提前退出函数要释放内存
								if(Users_ProcessDeleteOneKeys(keysType, i) == SUCCESS)
								{
									return i;
								}
								else
								{
									return USERS_DEL_ERR;
								}
							}
							break;
						case USERS_TYPE_CARD:
							if(memcmp(data, cardData[i].card, len) == 0)//如果匹配成功,则进行删除
							{
								OSAL_Free(buffer);//提前退出函数要释放内存
								if(Users_ProcessDeleteOneKeys(keysType, i) == SUCCESS)
								{
									return i;
								}
								else
								{
									return USERS_DEL_ERR;
								}
							}
							break;
						case USERS_TYPE_FACE:
							if(memcmp(data, &faceData[i].faceID, len) == 0)//如果匹配成功,则进行删除
							{
								OSAL_Free(buffer);//提前退出函数要释放内存
								if(Users_ProcessDeleteOneKeys(keysType, i) == SUCCESS)
								{
									return i;
								}
								else
								{
									return USERS_DEL_ERR;
								}
							}
							break;
					#if defined(FINGERVEIN_SUPPORT)	
						case USERS_TYPE_FVN:
							if(memcmp(data, &fvnData[i].fvn, len) == 0)//如果匹配成功,则进行删除
							{
								OSAL_Free(buffer);//提前退出函数要释放内存
								if(Users_ProcessDeleteOneKeys(keysType, i) == SUCCESS)
								{
									return i;
								}
								else
								{
									return USERS_DEL_ERR;
								}
							}
							break;
					#endif
					#if defined(PVN_SUPPORT)
					case USERS_TYPE_PVN:
						if(memcmp(data, &pvnData[i].pvnID, len) == 0)//如果匹配成功,则进行删除
						{
							OSAL_Free(buffer);//提前退出函数要释放内存
							if(Users_ProcessDeleteOneKeys(keysType, i) == SUCCESS)
							{
								return i;
							}
							else
							{
								return USERS_DEL_ERR;
							}
						}
						break;
					#endif
					#if defined(EVIDENCE_SUPPORT)
					case USERS_TYPE_EVIDENCE:
					{
						if(memcmp(data, &evidenceData[i].EvidenceId, len) == 0)//如果匹配成功,则进行删除
						{
							OSAL_Free(buffer);//提前退出函数要释放内存
							if(Users_ProcessDeleteOneKeys(keysType, i) == SUCCESS)
							{
								return i;
							}
							else
							{
								return USERS_DEL_ERR;
							}
						}
						break;
					}
					#endif
						default:
							break;
					}
				}
			}
			OSAL_Free(buffer);
			return USERS_DEL_ERR;
		}
	}
}

/**
  * @brief  删除一次性用户    
  * @note   
  * 
  * @param  keysType：密钥类型
  * @param  keysNum：密钥编号
  * 
  * @return 删除成功返回SUCCESS,否则返回ERROR
  */
static ErrorStatus Users_DelOnce(uint8_t *keysType, uint8_t *keysNum)
{
	if (g_onceKeysType != 0XFF)
	{
		Users_ProcessDeleteOneKeys(g_onceKeysType, g_onceKeysNum);
		*keysType = g_onceKeysType;
		*keysNum = g_onceKeysNum;
		g_onceKeysType = 0XFF;
		g_onceKeysNum = 0XFF;
		return SUCCESS;
	}
	*keysType = 0XFF;
	*keysNum = 0XFF;
	return ERROR;
}

/**
  * @brief  获取有效的用户编号,自动编号处理（添加密钥时）
  *
  * @param  keysType：密钥类型
  * 
  * @return 0xff：无可用编号，其余：可用的密钥编号
  */
static uint8_t Users_GetValidId(uint8_t keysType)
{
	uint8_t *map, qty = 0;

	if((keysType == USERS_TYPE_PWD)
		|| (keysType == USERS_TYPE_FPT)
		|| (keysType == USERS_TYPE_CARD)
		|| (keysType == USERS_TYPE_FACE)
	#if defined(FINGERVEIN_SUPPORT)
		|| (keysType == USERS_TYPE_FVN)
	#endif
	#if defined(PVN_SUPPORT)
		|| (keysType == USERS_TYPE_PVN)
	#endif
	#if defined(EVIDENCE_SUPPORT)
		|| (keysType == USERS_TYPE_EVIDENCE)
	#endif
	  )
	{
		qty = Users_GetKeysQty(keysType);
		map = Users_GetKeysMap(keysType);
	}
	else
	{
		USERS_LOG("Users_GetValidId error\r\n");
		return 0XFF;
	}

	for (int i = 0; i < qty; i++)
	{

		/* 过滤管理指纹 */
	#if !defined(ADMIN_FPT_DISABLE)
		if (keysType == USERS_TYPE_FPT && i == 0)
		{
			continue;
		}
	#endif
	#if defined(FINGERVEIN_SUPPORT)
		/* 过滤管理员指静脉 */
		if (keysType == USERS_TYPE_FVN && i == 0)
		{
			continue;
		}
	#endif
	#if defined(PVN_SUPPORT)
		/* 过滤管理员掌静脉 */
		if (keysType == USERS_TYPE_PVN && i == 0)
		{
			continue;
		}
	#endif
	#if defined(EVIDENCE_SUPPORT)
		/* 过滤管理员凭证 */
		// if (keysType == USERS_TYPE_EVIDENCE && i == 0)
		// {
		// 	continue;
		// }
	#endif
		/* 过滤管理密码 */
    #if defined(DXTC_NO_MENU)
        {
            if (keysType == USERS_TYPE_PWD && i == 0)
            {
                continue;
            }
        }
	#endif
		if ((map[i / 8] & (1 << (i % 8))) == 0)
		{
			return i;
		}
	}
	return 0XFF;
}

/**
  * @brief  获取有效的用户数量      
  * @note   
  * 
  * @param  keysType:秘钥类型
  * 
  * @param  opt: opt为1时，所有类型都统计, opt为0时，仅统计永久类型秘钥（永久、胁迫、管理）
  */
static uint8_t Users_GetQty(uint8_t keysType, uint8_t opt)
{
	uint8_t *map, len, qty = 0;

	if((keysType != USERS_TYPE_PWD)
		&& (keysType != USERS_TYPE_FPT)
		&& (keysType != USERS_TYPE_CARD)
		&& (keysType != USERS_TYPE_FACE)
	#if defined(FINGERVEIN_SUPPORT)
		&& (keysType != USERS_TYPE_FVN)
	#endif
	#if defined(PVN_SUPPORT)
		&& (keysType != USERS_TYPE_PVN)
	#endif
	#if defined(EVIDENCE_SUPPORT)
		&& (keysType != USERS_TYPE_EVIDENCE)
	#endif
	  )//参数合法性检查
	{
		return 0;
	}
	len = Users_GetKeysQty(keysType);
	map = Users_GetKeysMap(keysType);
	
	if(opt)//所有类型都统计,此时只需查map表即可
	{
		for (int i = 0; i < len; i++)
		{
			#if !defined(ADMIN_FPT_DISABLE)
				if (i == 0 && keysType == USERS_TYPE_FPT)
				{
					//管理员指纹不算指纹数量
				}
				else 
			#endif
			#if defined(DXTC_NO_MENU)
				if (i == 0 && keysType == USERS_TYPE_PWD)
				{
					//管理员密码不算密码数量
				}
				else
			#endif
			#if defined(FINGERVEIN_SUPPORT)
				if (i == 0 && keysType == USERS_TYPE_FVN)
				{
					//管理员指静脉不算指静脉数量
				}
				else
			#endif
			#if defined(PVN_SUPPORT)
				// if (i == 0 && keysType == USERS_TYPE_PVN)
				// {
				// 	//管理员掌静脉不算掌静脉数量
				// }
				// else
			#endif
			#if defined(EVIDENCE_SUPPORT)
				// if (i == 0 && keysType == USERS_TYPE_EVIDENCE)
				// {
				// 	//管理员掌静脉不算掌静脉数量
				// }
//				else
			#endif
			if (map[i / 8] & (1 << (i % 8)))
			{
				qty++;
			}
		}
	}	
	else//仅统计永久类型秘钥,此时查完map表,还需查询每个有效用户秘钥的类型是否是永久类型
	{
		uint8_t *buffer = NULL;
		uint8_t  attr;	//钥匙属性
		uint32_t addr, size;
		NvPassword_stu_t *pwdData = NULL;
		NvFpt_stu_t *fptData = NULL;
		NvCard_stu_t *cardData = NULL;
		NvFace_stu_t *faceData = NULL;
	#if defined(FINGERVEIN_SUPPORT)
		NvFvn_stu_t *fvnData = NULL;
	#endif
	#if defined(PVN_SUPPORT)
		NvPvn_stu_t *pvnData = NULL;
	#endif
	#if defined(EVIDENCE_SUPPORT)
		NvEvidence_stu_t *evidenceData = NULL;
	#endif

		addr = Users_GetKeysDataAddr(keysType);
		size = Users_GetKeysDataSize(keysType);

		buffer = (uint8_t *)OSAL_Malloc(size);
		if (buffer == NULL)
		{
			return 0;
		}
		OSAL_NvRead(addr, buffer, size);

		pwdData = (NvPassword_stu_t *)buffer;
		fptData = (NvFpt_stu_t *)buffer;
		cardData = (NvCard_stu_t *)buffer;
		faceData = (NvFace_stu_t *)buffer;
	#if defined(FINGERVEIN_SUPPORT)
		fvnData = (NvFvn_stu_t *)buffer;
	#endif
	#if defined(PVN_SUPPORT)
		pvnData = (NvPvn_stu_t *)buffer;
	#endif
	#if defined(EVIDENCE_SUPPORT)
		evidenceData = (NvEvidence_stu_t *)buffer;
	#endif

		for (int i = 0; i < len; i++)
		{
		#if !defined(ADMIN_FPT_DISABLE)
			if (i == 0 && keysType == USERS_TYPE_FPT)
			{
				//管理员指纹不算指纹数量
			}
			else 
		#endif
		#if defined(DXTC_NO_MENU)
			if (i == 0 && keysType == USERS_TYPE_PWD)
			{
				//管理员密码不算密码数量
			}
			else
		#endif
		#if defined(FINGERVEIN_SUPPORT)
			if (i == 0 && keysType == USERS_TYPE_FVN)
			{
				//管理员指静脉不算指静脉数量
			}
			else
		#endif 
		#if defined(PVN_SUPPORT)
			if (i == 0 && keysType == USERS_TYPE_PVN)
			{
				//管理掌静脉不算掌静脉数量
			}
			else
		#endif 
			if ( map[i / 8] & (1 << (i % 8)) ) //当前用户有效的时候才进行检查密钥属性
			{
				switch (keysType)
				{
					case USERS_TYPE_PWD:
						attr = pwdData[i].attr;
						break;
					case USERS_TYPE_FPT:
						attr = fptData[i].attr;
						break;
					case USERS_TYPE_CARD:
						attr = cardData[i].attr;
						break;
					case USERS_TYPE_FACE:
						attr = faceData[i].attr;
						break;
				#if defined(FINGERVEIN_SUPPORT)
					case USERS_TYPE_FVN:
						attr = fvnData[i].attr;
						break;
				#endif
				#if defined(PVN_SUPPORT)
					case USERS_TYPE_PVN:
						attr = pvnData[i].attr;
						break;
				#endif
				#if defined(EVIDENCE_SUPPORT)
					case USERS_TYPE_EVIDENCE:
						attr = evidenceData[i].attr;
						break;
				#endif
					default:
						break;
				}
				if(attr == USERS_ATTR_FOREVER || attr == USERS_ATTR_URGENT || attr == USERS_ATTR_ADMIN)
				{
					qty++;
				}
			}
		}
		OSAL_Free(buffer);
	}
	USERS_LOG("keysType:%d, qty:%d\r\n", keysType, qty);
	return qty;
}

/**
  * @brief  获取密钥列表
  * @param  keysList：密钥列表
  * @param  keysType：密钥类型
  * 
  * @return 成功返回SUCCESS, 失败返回ERROR
  */
static ErrorStatus Users_GetList(KeyList_stu_t keysList[], uint8_t keysType)
{
	uint8_t keysQty = 0;
	uint32_t addr, size;
	uint8_t *buffer = NULL;
	NvPassword_stu_t *pwdData = NULL;
	NvFpt_stu_t *fptData = NULL;
	NvCard_stu_t *cardData = NULL;
	NvFace_stu_t *faceData = NULL;
#if defined(FINGERVEIN_SUPPORT)
	NvFvn_stu_t *fvnData = NULL;
#endif
#if defined(PVN_SUPPORT)
	NvPvn_stu_t *pvnData = NULL;
#endif
#if defined(EVIDENCE_SUPPORT)
	NvEvidence_stu_t *evidenceData = NULL;
#endif

	if (keysList == NULL)
	{
		return ERROR;
	}
	if((keysType != USERS_TYPE_PWD)
		&& (keysType != USERS_TYPE_FPT)
		&& (keysType != USERS_TYPE_CARD)
        && (keysType != USERS_TYPE_FACE)
	#if defined(FINGERVEIN_SUPPORT)
		&& (keysType != USERS_TYPE_FVN)
	#endif
	#if defined(PVN_SUPPORT)
		&& (keysType != USERS_TYPE_PVN)
	#endif
	#if defined(EVIDENCE_SUPPORT)
		&& (keysType != USERS_TYPE_EVIDENCE)
	#endif
	  )//参数合法性检查
	{
		return ERROR;
	}

	keysQty = Users_GetKeysQty(keysType);
	addr = Users_GetKeysDataAddr(keysType);
	size = Users_GetKeysDataSize(keysType);
	buffer = (uint8_t *)OSAL_Malloc(size);
	USERS_LOG("keysType: %d, addr: 0x%08x, size: %d\r\n", keysType, addr, size);
	if (buffer == NULL)
	{
		USERS_LOG("buffer malloc error\r\n");
		return ERROR;
	}
	OSAL_NvRead(addr, buffer, size);

	memset(keysList, 0xFF, keysQty * sizeof(KeyList_stu_t));
	for (int i=0; i<keysQty; i++)
	{
		if (Users_ReadKeysNumStatus(keysType, i) == USERS_NUMBER_EXISTED)
		{
			switch (keysType)
			{
				case USERS_TYPE_PWD:
					pwdData = (NvPassword_stu_t *)buffer;
					keysList[i].attr = pwdData[i].attr;
                    keysList[i].week = pwdData[i].week;
                    keysList[i].stime = pwdData[i].stime;
                    keysList[i].etime = pwdData[i].etime;
                    keysList[i].creatTime = pwdData[i].ctime;
					break;
				case USERS_TYPE_FPT:
					fptData = (NvFpt_stu_t *)buffer;
					keysList[i].attr = fptData[i].attr;
                    keysList[i].week = fptData[i].week;
                    keysList[i].stime = fptData[i].stime;
                    keysList[i].etime = fptData[i].etime;
                    keysList[i].creatTime = fptData[i].ctime;
					break;
				case USERS_TYPE_CARD:
					cardData = (NvCard_stu_t *)buffer;
                    keysList[i].attr = cardData[i].attr;
                    keysList[i].week = cardData[i].week;
                    keysList[i].stime = cardData[i].stime;
                    keysList[i].etime = cardData[i].etime;
                    keysList[i].creatTime = cardData[i].ctime;
					break;
				case USERS_TYPE_FACE:
					faceData = (NvFace_stu_t *)buffer;
                    keysList[i].attr = faceData[i].attr;
                    keysList[i].week = faceData[i].week;
                    keysList[i].stime = faceData[i].stime;
                    keysList[i].etime = faceData[i].etime;
                    keysList[i].creatTime = faceData[i].ctime;
					break;
			#if defined(FINGERVEIN_SUPPORT)
				case USERS_TYPE_FVN:
					fvnData = (NvFvn_stu_t *)buffer;
					keysList[i].attr = fvnData[i].attr;
                    keysList[i].week = fvnData[i].week;
                    keysList[i].stime = fvnData[i].stime;
                    keysList[i].etime = fvnData[i].etime;
                    keysList[i].creatTime = fvnData[i].ctime;
					break;
			#endif
			#if defined(PVN_SUPPORT)
				case USERS_TYPE_PVN:
					pvnData = (NvPvn_stu_t *)buffer;
					keysList[i].attr = pvnData[i].attr;
                    keysList[i].week = pvnData[i].week;
                    keysList[i].stime = pvnData[i].stime;
                    keysList[i].etime = pvnData[i].etime;
                    keysList[i].creatTime = pvnData[i].ctime;
					break;
			#endif
			#if defined(EVIDENCE_SUPPORT)
				case USERS_TYPE_EVIDENCE:
					evidenceData = (NvEvidence_stu_t *)buffer;
					keysList[i].attr = evidenceData[i].attr;
                    keysList[i].week = evidenceData[i].week;
                    keysList[i].stime = evidenceData[i].stime;
                    keysList[i].etime = evidenceData[i].etime;
                    keysList[i].creatTime = evidenceData[i].ctime;
					break;
			#endif
			}
		}
	}
	OSAL_Free(buffer);
	return SUCCESS;
}

/**
  * @brief  检查管理密码
  *         
  * @note   
  */
static ErrorStatus Users_CheckAdmin(uint8_t keysType)
{
	if(keysType == USERS_TYPE_PWD)
	{
	#if defined(DXTC_NO_MENU)
		if(Users_FindKeys(USERS_TYPE_PWD, 0))//管理密码已占用,表示已添加管理密码
		{
			return SUCCESS;
		}
		else
		{
			return ERROR;
		}
	#else
		uint8_t pwd[] = DEFAULT_ADMIN_PWD; //初始管理密码赋值
		// if(sizeof(pwd) == sizeof(gUsersParam.admin_pwd))
		{
			USERS_LOG("gUsersParam.admin_pwd[0]:%02X, %02X %02X\r\n", keysType, gUsersParam.admin_pwd[0],gUsersParam.admin_pwd[7]);
			if ( memcmp(gUsersParam.admin_pwd, pwd, sizeof(pwd))  == 0)
			{
				return SUCCESS;
			}
		}
		return ERROR;
	#endif
	}
	#if !defined(ADMIN_FPT_DISABLE)
	else if(keysType == USERS_TYPE_FPT)
	{
		if(KEYS_QTY_FPT == 0 || Users_FindKeys(USERS_TYPE_FPT, 0))//管理指纹已占用,表示已添加管理指纹密码
		{
			return SUCCESS;
		}
		else
		{
			return ERROR;
		}
	}
	#endif
	#if defined(FINGERVEIN_SUPPORT)
	else if(keysType == USERS_TYPE_FVN)
	{
		if(Users_FindKeys(USERS_TYPE_FVN, 0))
		{
			return SUCCESS;		//指静脉的密钥0为空,表示管理指静脉未添加
		}
		else
		{
			return ERROR;	//管理指静脉已占用,表示已添加管理指静脉
		}
	}
	#endif
	#if defined(PVN_SUPPORT)
	else if(keysType == USERS_TYPE_PVN)
	{
		if(Users_FindKeys(USERS_TYPE_PVN, 0))
		{
			return SUCCESS;		//掌静脉的密钥0为空,表示管理掌静脉未添加
		}
		else
		{
			return ERROR;	//管理掌静脉已占用,表示已添加管理掌静脉
		}
	}
	#endif
	#if defined(EVIDENCE_SUPPORT)
	else if(keysType == USERS_TYPE_EVIDENCE)
	{
		if(Users_FindKeys(USERS_TYPE_EVIDENCE, 0))
		{
			return SUCCESS;		//凭证的密钥0为空,表示管理凭证未添加
		}
		else
		{
			return ERROR;	//管理凭证已占用,表示已添加管理凭证
		}
	}
	#endif
	else
	{
		return ERROR;
	}
}

/**
  * @brief  获取密钥策略
  *         
  * @note   
  * @param  keysType：密钥类型
  * @param  keysNum：密钥编号
  * @param  pAttrPloy：保存获取的密码策略属性
  * 
  * @return 获取成功返回SUCCESS, 否则返回ERROR
  */
static ErrorStatus Users_GetAttrPloy(uint8_t keysType, uint8_t keysNum, UserAttrPloy_stu_t *pAttrPloy)
{
	if(pAttrPloy == NULL)
	{
		return ERROR;
	}
	
	if(Users_FindKeys(keysType, keysNum) == SUCCESS)
	{
		return ERROR; //不存在的密钥编号不能读取
	}

	if(keysType == USERS_TYPE_PWD)
	{
		if(keysNum >= KEYS_QTY_PWD)
		{
			return ERROR;
		}
		else
		{
			return OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, pwdData[keysNum].attr), pAttrPloy, sizeof(UserAttrPloy_stu_t));
		}
	}
	else if(keysType == USERS_TYPE_FPT)
	{
		if(keysNum >= KEYS_QTY_FPT)
		{
			return ERROR;
		}
		else
		{
			return OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, fptData[keysNum].attr), pAttrPloy, sizeof(UserAttrPloy_stu_t));
		}
	}
	else if(keysType == USERS_TYPE_CARD)
	{
		if(keysNum >= KEYS_QTY_CARD)
		{
			return ERROR;
		}
		else
		{
			return OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, cardData[keysNum].attr), pAttrPloy, sizeof(UserAttrPloy_stu_t));
		}
	}
	else if(keysType == USERS_TYPE_FACE)
	{
		if(keysNum >= KEYS_QTY_FACE)
		{
			return ERROR;
		}
		else
		{
			return OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, faceData[keysNum].attr), pAttrPloy, sizeof(UserAttrPloy_stu_t));
		}
	}
	#if defined(FINGERVEIN_SUPPORT)
	else if(keysType == USERS_TYPE_FVN)
	{
		if(keysNum >= KEYS_QTY_FVN)
		{
			return ERROR;
		}
		else
		{
			return OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, fvnData[keysNum].attr), pAttrPloy, sizeof(UserAttrPloy_stu_t));
		}
	}
	#endif
	#if defined(PVN_SUPPORT)
	else if(keysType == USERS_TYPE_PVN)
	{
		if(keysNum >= KEYS_QTY_PVN)
		{
			return ERROR;
		}
		else
		{
			return OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, pvnData[keysNum].attr), pAttrPloy, sizeof(UserAttrPloy_stu_t));
		}
	}
	#endif
	#if defined(EVIDENCE_SUPPORT)
	else if(keysType == USERS_TYPE_EVIDENCE)
	{
		if(keysNum >= USERS_TYPE_EVIDENCE)
		{
			return ERROR;
		}
		else
		{
			return OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, evidenceData[keysNum].attr), pAttrPloy, sizeof(UserAttrPloy_stu_t));
		}
	}
	#endif
	else
	{
		return ERROR;
	}
}

/**
  * @brief  设置密钥策略     
  * @note   如果没有策略,则pAttrPloy->ploy传NULL即可
  * 
  * @param  keysType：密钥类型
  * @param  keysNum：密钥编号
  * @param  pAttrPloy：设置的密码策略属性
  * 
  * @return 设置成功返回SUCCESS, 否则返回ERROR
  */
static ErrorStatus Users_SetAttrPloy(uint8_t keysType, uint8_t keysNum, uint8_t attr, UserPloy_stu_t *pPloy)
{
	UserAttrPloy_stu_t pAttrPloy; 
	
	pAttrPloy.attr = attr;
	if(pPloy != NULL)
	{
		memcpy(&(pAttrPloy.ploy),pPloy,sizeof(UserPloy_stu_t));
	}
	
	USERS_LOG("SetAttr %d , %d...%x",keysType,keysNum,pAttrPloy.attr);
	// 互联互通协议  密钥属性和策略是分开设置的
	// if( (pAttrPloy.attr == USERS_ATTR_PLOY || pAttrPloy.attr == USERS_ATTR_ONCE_PLOY) && pPloy == NULL)
	// {
	// 	USERS_LOG("111...");
	// 	return ERROR;//若属性设置为策略模式而策略内容为空,则返回错误
	// }

	if(Users_FindKeys(keysType, keysNum) == SUCCESS)
	{
		return ERROR; //不存在的密钥编号不能读取
	}
	
	if(keysType == USERS_TYPE_PWD)
	{
		if(keysNum >= KEYS_QTY_PWD)
		{
			return ERROR;
		}
		else
		{
			if(pPloy == NULL)//为空时,只写密钥属性,不写密钥策略内容
			{
				return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, pwdData[keysNum].attr), &pAttrPloy.attr, sizeof(uint8_t));
			}
			else
			{
				return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, pwdData[keysNum].attr), &pAttrPloy, sizeof(UserAttrPloy_stu_t));
			}
		}
	}
	else if(keysType == USERS_TYPE_FPT)
	{
		if(keysNum >= KEYS_QTY_FPT)
		{
			return ERROR;
		}
		else
		{
			if(pPloy == NULL)//为空时,只写密钥属性,不写密钥策略内容
			{
				return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, fptData[keysNum].attr), &pAttrPloy.attr, sizeof(uint8_t));
			}
			else
			{
				return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, fptData[keysNum].attr), &pAttrPloy, sizeof(UserAttrPloy_stu_t));
			}
		}
	}
	else if(keysType == USERS_TYPE_CARD)
	{
		if(keysNum >= KEYS_QTY_CARD)
		{
			return ERROR;
		}
		else
		{
			if(pPloy == NULL)//为空时,只写密钥属性,不写密钥策略内容
			{
				return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, cardData[keysNum].attr), &pAttrPloy.attr, sizeof(uint8_t));
			}
			else
			{
				return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, cardData[keysNum].attr), &pAttrPloy, sizeof(UserAttrPloy_stu_t));
			}
		}
	}
	else if(keysType == USERS_TYPE_FACE)
	{
		if(keysNum >= KEYS_QTY_FACE)
		{
			return ERROR;
		}
		else
		{
			if(pPloy == NULL)//为空时,只写密钥属性,不写密钥策略内容
			{
				return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, faceData[keysNum].attr), &pAttrPloy.attr, sizeof(uint8_t));
			}
			else
			{
				return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, faceData[keysNum].attr), &pAttrPloy, sizeof(UserAttrPloy_stu_t));
			}
		}
	}
#if defined(FINGERVEIN_SUPPORT)
	else if(keysType == USERS_TYPE_FVN)
	{
		if(keysNum >= KEYS_QTY_FVN)
		{
			return ERROR;
		}
		else
		{
			if(pPloy == NULL)//为空时,只写密钥属性,不写密钥策略内容
			{
				return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, fvnData[keysNum].attr), &pAttrPloy.attr, sizeof(uint8_t));
			}
			else
			{
				return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, fvnData[keysNum].attr), &pAttrPloy, sizeof(UserAttrPloy_stu_t));
			}
		}
	}
#endif
#if defined(PVN_SUPPORT)
	else if(keysType == USERS_TYPE_PVN)
	{
		if(keysNum >= KEYS_QTY_PVN)
		{
			return ERROR;
		}
		else
		{
			if(pPloy == NULL)//为空时,只写密钥属性,不写密钥策略内容
			{
				return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, pvnData[keysNum].attr), &pAttrPloy.attr, sizeof(uint8_t));
			}
			else
			{
				return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, pvnData[keysNum].attr), &pAttrPloy, sizeof(UserAttrPloy_stu_t));
			}
		}
	}
#endif
#if defined(EVIDENCE_SUPPORT)
	else if(keysType == USERS_TYPE_EVIDENCE)
	{
		if(keysNum >= KEYS_QTY_EVIDENCE)
		{
			return ERROR;
		}
		else
		{
			if(pPloy == NULL)//为空时,只写密钥属性,不写密钥策略内容
			{
				return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, evidenceData[keysNum].attr), &pAttrPloy.attr, sizeof(uint8_t));
			}
			else
			{
				return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, evidenceData[keysNum].attr), &pAttrPloy, sizeof(UserAttrPloy_stu_t));
			}
		}
	}
#endif
	else
	{
		return ERROR;
	}
}

/**
  * @brief  设置安全模式     
  * @note 
  * 
  * @param  flag：SET:打开 RESET:关闭
  * 
  * @return 设置成功返回SUCCESS, 否则返回ERROR
  */
static ErrorStatus Users_SetSafeMode(FlagStatus flag)
{
	if(flag)//打开安全模式需要查询指纹和卡片密匙的数量
	{
		if(gUsersParam.qty.fpt == 0 && gUsersParam.qty.card == 0 )
		{
			return ERROR;
		}
	}
	gUsersParam.dual_verify = (uint8_t)flag;
	OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam.dual_verify), &gUsersParam.dual_verify, sizeof(gUsersParam.dual_verify));
	return SUCCESS;
}

/**
  * @brief  获取安全模式标志位    
  * @note   
  * 
  * @return 若安全模式打开则返回SET, 否则返回RESET
  */
static FlagStatus Users_GetSafeMode(void)
{
	if (gUsersParam.dual_verify)//打开了安全模式
	{
		return SET;
	}
	return RESET;
}

/**
  * @brief  设置激活码
  * @note   
  * 
  * @param  activeCode:激活码
  * 
  * @return 设置成功返回SUCCESS, 否则返回ERROR
  */
static ErrorStatus Users_SetActiveCode(uint8_t activeCode[])
{
	memcpy(gUsersParam.activeCodeHash, activeCode, 21);
	OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam.activeCodeHash), &gUsersParam.activeCodeHash, sizeof(gUsersParam.activeCodeHash));
	return SUCCESS;
}

/**
  * @brief  获取激活码
  * @note   
  * 
  * @param  activeCode:激活码
  * 
  * @return 激活码存在返回SUCCESS, 否则返回ERROR
  */
static ErrorStatus Users_GetActiveCode(uint8_t activeCode[])
{
	return Users_ReadActivationCode(activeCode);
}

/**
  * @brief  设置激活码状态
  * @note   
  * 
  * @param  status，0：反激活，1：激活
  * 
  * @return 成功返回SUCCESS, 否则返回ERROR
  */
static ErrorStatus Users_SetActiveCodeStatus(uint8_t status)
{
	gUsersParam.activeCodeHash[20] = status; //设置激活标志
	return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam.activeCodeHash), &gUsersParam.activeCodeHash, sizeof(gUsersParam.activeCodeHash));
}

/**
  * @brief  设置密钥数量
  * @note   
  * 
  * @param	keysType：秘钥类型  keysQty：秘钥数量
  * 
  * @return 设置成功则返回SUCCESS, 否则返回ERROR
  */
static ErrorStatus Users_SetKeysQty(uint8_t keysType, uint16_t keysQty)
{
	switch (keysType)
	{
		case USERS_TYPE_PWD:
			if(keysQty > KEYS_MAX_QTY_PWD || keysQty < 1)
			{
				return ERROR;
			}
			else
			{
				gUsersParam.qty.pwd = keysQty;
			}
			break;
		case USERS_TYPE_FPT:
			if(keysQty > KEYS_MAX_QTY_FPT)
			{
				return ERROR;
			}
			else
			{
				gUsersParam.qty.fpt = keysQty;
			}
			break;
		case USERS_TYPE_CARD:
			if(keysQty > KEYS_MAX_QTY_CARD)
			{
				return ERROR;
			}
			else
			{
				gUsersParam.qty.card = keysQty;
			}
			break;
		case USERS_TYPE_FACE:
			if(keysQty > KEYS_MAX_QTY_FACE)
			{
				return ERROR;
			}
			else
			{
				gUsersParam.qty.face = keysQty;
			}
			break;
		case USERS_TYPE_PLOY_PWD:
			gUsersParam.qty_ploy_pwd = keysQty;
			return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam.qty_ploy_pwd), &gUsersParam.qty_ploy_pwd, sizeof(gUsersParam.qty_ploy_pwd)); //存储密钥数量
	#if defined(FINGERVEIN_SUPPORT)
		case USERS_TYPE_FVN:
			if(keysQty > KEYS_MAX_QTY_FVN)
			{
				return ERROR;
			}
			else
			{
				gUsersParam.qty.fvn = keysQty;
			}
			break;
	#endif
	#if defined(PVN_SUPPORT)
		case USERS_TYPE_PVN:
			if(keysQty > KEYS_MAX_QTY_PVN)
			{
				return ERROR;
			}
			else
			{
				gUsersParam.qty.pvn = keysQty;
			}
			break;
	#endif
	#if defined(EVIDENCE_SUPPORT)
		case USERS_TYPE_EVIDENCE:
			if(keysQty > KEYS_MAX_QTY_EVIDENCE)
			{
				return ERROR;
			}
			else
			{
				gUsersParam.qty.evidence = keysQty;
			}
			break;
	#endif
		default:
			return ERROR;
	}
	return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam.qty), &gUsersParam.qty, sizeof(gUsersParam.qty)); //存储密钥数量
}

/**
  * @brief  设置产测标志
  * @note
  *
  * @param	flag
  * 
  * @return 设置成功则返回SUCCESS, 否则返回ERROR
  */
static ErrorStatus Users_SetAteFlag(ErrorStatus flag)
{
	if (flag == ERROR)
	{
		memset((uint8_t *)&gUsersParam.qty, 0x00, sizeof(gUsersParam.qty));
	}
	gUsersParam.ate_flag = ((flag == SUCCESS) ? USARS_NV_INIT_FLAG : 0x00);
	return OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam.ate_flag), &gUsersParam.ate_flag, sizeof(gUsersParam.ate_flag)); //存储产测标志
}

/**
  * @brief  获取对应秘钥类型的数量
  * @note
  *
  * @param	keysType：秘钥类型
  * 
  * @return 返回数量
  */
static uint16_t Users_GetKeysQty(uint8_t keysType)
{
    uint16_t num =0;
	switch (keysType)
	{
		case USERS_TYPE_PWD:
			num = KEYS_QTY_PWD;
			break;
		case USERS_TYPE_FPT:
			num = KEYS_QTY_FPT;
			break;
		case USERS_TYPE_CARD:
			num = KEYS_QTY_CARD;
			break;
        case USERS_TYPE_FACE:
            num =  KEYS_QTY_FACE;
            break;
		case USERS_TYPE_PLOY_PWD: //策略密钥数量
			num = gUsersParam.qty_ploy_pwd;
			break;
	#if defined(FINGERVEIN_SUPPORT)
		case USERS_TYPE_FVN:
            num =  KEYS_QTY_FVN;
            break;
	#endif
	#if defined(PVN_SUPPORT)
		case USERS_TYPE_PVN:
            num =  KEYS_QTY_PVN;
            break;
	#endif
	#if defined(EVIDENCE_SUPPORT)
		case USERS_TYPE_EVIDENCE:
            num =  KEYS_QTY_EVIDENCE;
            break;
	#endif
		default:
            num = 0;
        break;
	}
	USERS_LOG("keysType:%d,total num:%d\r\n",keysType,num);
    return num;
}

#if defined(DXTC_NO_MENU)
static ErrorStatus Users_OfflinePwd_CreateFactor(uint8_t *pFactor, uint8_t opt, uint8_t eSN[], uint8_t eSNLen)
{
    memset((uint8_t *)&gUsersParam.offlinePwd, 0, sizeof(gUsersParam.offlinePwd));
    memcpy(gUsersParam.offlinePwd.bleSN, eSN, eSNLen); //蓝牙esn
    memcpy(gUsersParam.offlinePwd.random, pFactor, OFFLINE_PWD_RANDOM_LEN); //随机数
    
    /* 存储离线密钥数据 */
    if(OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam.offlinePwd), &gUsersParam.offlinePwd, sizeof(gUsersParam.offlinePwd)) != SUCCESS)
    {
        USERS_LOG("Save offline pwd info err!\r\n");
        return ERROR;
    }

    /* 打印随机数 */
    char string[OFFLINE_PWD_RANDOM_LEN * 2 + 1] = {0};
    for (int i=0; i<OFFLINE_PWD_RANDOM_LEN; i++)
    {
        sprintf(&string[i*2], "%02x", pFactor[i]);
    }
    USERS_LOG("Save random:%s", string);

	return SUCCESS;
}
#else
static ErrorStatus Users_OfflinePwd_CreateFactor(uint8_t *pFactor, uint8_t opt, uint8_t eSN[], uint8_t eSNLen)
{
    uint8_t random_crc[OFFLINE_PWD_RANDOM_LEN + 4] = {0};
    uint8_t aes_key[32] = {0};
    uint8_t admin_len;
    uint32_t crc32 = 0;
    char string[80] = {0};
	/* 赋值bleSN */
	memcpy(gUsersParam.offlinePwd.bleSN, eSN, eSNLen);
	//保存
	OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam.offlinePwd.bleSN), &gUsersParam.offlinePwd.bleSN, sizeof(gUsersParam.offlinePwd.bleSN));
    for(uint8_t i = 0;i<7;i++)
    {
        OSAL_Crypto(CALC_RANDOM_NUMBER,NULL,0,&offline_pwd_random[4*i],0);
    }
    memcpy(random_crc, offline_pwd_random, OFFLINE_PWD_RANDOM_LEN);
    OSAL_Crypto(CALC_CRC32,random_crc,OFFLINE_PWD_RANDOM_LEN,&crc32,0);
    USERS_LOG("random_crc: %X\r\n", crc32);
    memcpy(&random_crc[OFFLINE_PWD_RANDOM_LEN], &crc32, sizeof(crc32));
    /* 打印随机数和CRC */
    for (int i=0; i<OFFLINE_PWD_RANDOM_LEN; i++)
    {
        sprintf(&string[i*2], "%02x", random_crc[i]);
    }
    sprintf(&string[28*2], "%02X%02X%02X%02X", random_crc[28], random_crc[29], random_crc[30], random_crc[31]);
    USERS_LOG("random_crc: %s\r\n", string);
    admin_len = Users_GetKeysLen(gUsersParam.admin_pwd, PWD_LEN_MAX);
    memset(string, 0, 80);
    for (int i=0; i<admin_len; i++)
    {
        sprintf(&string[i], "%d",  gUsersParam.admin_pwd[i]);
    }
    USERS_LOG("admin_pwd:  %s", string);
    /* 管理密码经过SHA256得到32字节数据作为AES的KEY */
    if(OSAL_Crypto(CALC_SHA256,gUsersParam.admin_pwd,admin_len,aes_key,NULL) !=SUCCESS)
    {
        USERS_LOG("SHA256 error !\r\n");
    }
    /* 打印AES256-KEY */
    memset(string, 0, 80);
    for (int i=0; i<32; i++)
    {
        sprintf(&string[i*2], "%02X", aes_key[i]);
    }
    USERS_LOG("aes_key:    %s\r\n", string);
     /* 加密随机数和CRC，得到32字节因子 */
    if(OSAL_Crypto(AES256_ENCRYPTION,random_crc,16,pFactor,aes_key) !=SUCCESS)
    {
        USERS_LOG("AES256 error !\r\n");
    }

    if (OSAL_Crypto(AES256_ENCRYPTION,&random_crc[16],16, &pFactor[16],aes_key) != true)
    {
        USERS_LOG("AES256 error !\r\n");
        return ERROR;
    }
	/* 打印离线密码因子 */
    memset(string, 0, 80);
    for (int i=0; i<32; i++)
    {
        sprintf(&string[i*2], "%02X", pFactor[i]);
    }
    USERS_LOG("pFactor:    %s\r\n", string);
	return SUCCESS;
}
#endif

static ErrorStatus Users_OfflinePwd_SaveRandom(void)
{
    if(OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam.offlinePwd.random),offline_pwd_random,sizeof(offline_pwd_random)) !=SUCCESS)
    {
        USERS_LOG("Save offline pwd random error !\r\n");
        return ERROR;
    }
	memcpy(gUsersParam.offlinePwd.random, offline_pwd_random, sizeof(offline_pwd_random));
    /* 打印随机数 */
    char string[OFFLINE_PWD_RANDOM_LEN * 2 + 1] = {0};
    for (int i=0; i<OFFLINE_PWD_RANDOM_LEN; i++)
    {
        sprintf(&string[i*2], "%02x", offline_pwd_random[i]);
    }
    USERS_LOG("Save random:%s", string);
	return SUCCESS;
}


/**
  * @brief  设置胁迫密码报警功能开关
  * @note
  *
  * @param	Flag：0:关闭 1:打开
  * 
  * @return 返回结果
  */
static ErrorStatus Users_SetUrgent(FlagStatus Flag)
{
	gUsersParam.urgentFlag = (uint8_t)Flag;
	OSAL_NvWrite(OSAL_OFFSET(NvUsers_stu_t, usersParam.urgentFlag), &gUsersParam.urgentFlag, sizeof(gUsersParam.urgentFlag));
	return SUCCESS;
}

static FlagStatus Users_GetUrgent(void)
{
    FlagStatus flag = RESET; 
    OSAL_NvRead(OSAL_OFFSET(NvUsers_stu_t, usersParam.urgentFlag), &gUsersParam.urgentFlag, sizeof(gUsersParam.urgentFlag));
    flag = (gUsersParam.urgentFlag == 1) ? SET : RESET;
    return  flag;
}

static UsersNumStatus_enum_t Users_KeyNumIsExist(uint8_t keysType, uint8_t Num)
{
	uint8_t map = 0;
	if ( (keysType == USERS_TYPE_PWD  && Num >= KEYS_QTY_PWD)
		|| (keysType == USERS_TYPE_FPT  && Num >= KEYS_QTY_FPT)
		|| (keysType == USERS_TYPE_CARD && Num >= KEYS_QTY_CARD) 
	#if defined(FINGERVEIN_SUPPORT)
		|| (keysType == USERS_TYPE_FVN  && Num >= KEYS_QTY_FVN)
	#endif
	#if defined(PVN_SUPPORT)
		|| (keysType == USERS_TYPE_PVN  && Num >= KEYS_QTY_PVN)
	#endif
	#if defined(EVIDENCE_SUPPORT)
		|| (keysType == USERS_TYPE_EVIDENCE  && Num >= KEYS_QTY_EVIDENCE)
	#endif
	   )
	{
		return USERS_NUMBER_ERROR;
	}

	if (keysType == USERS_TYPE_PWD && Num < KEYS_QTY_PWD)
	{
		map = gUsersParam.pwd_map[Num/8];
	}
	else if (keysType == USERS_TYPE_FPT && Num < KEYS_QTY_FPT)
	{
		map = gUsersParam.fpt_map[Num/8];
	}
	else if (keysType == USERS_TYPE_CARD && Num < KEYS_QTY_CARD)
	{
		map = gUsersParam.card_map[Num/8];
	}
#if defined(FINGERVEIN_SUPPORT)
	else if (keysType == USERS_TYPE_FVN && Num < KEYS_QTY_FVN)
	{
		map = gUsersParam.fvn_map[Num/8];
	}
#endif
#if defined(PVN_SUPPORT)
	else if (keysType == USERS_TYPE_PVN && Num < KEYS_QTY_PVN)
	{
		map = gUsersParam.pvn_map[Num/8];
	}
#endif
#if defined(EVIDENCE_SUPPORT)
	else if (keysType == USERS_TYPE_EVIDENCE && Num < KEYS_QTY_EVIDENCE)
	{
		map = gUsersParam.evidence_map[Num/8];
	}
#endif
	else
	{
		return USERS_NUMBER_ERROR;//密钥类型或ID错误
	}

	if ((map & (1<<(Num%8))) == 0)
	{
		return USERS_NUMBER_IDLE;//该ID未占用
	}
	return USERS_NUMBER_EXISTED;
}

static uint8_t Users_CardIsExist(uint8_t* pdata, uint8_t len)
{
	if (len != 4 && len != 7 && len != 10)
	{
		return 0XFF; //非法卡片
	}
	/* 输入的卡片ID与卡片库比对 */
	NvCard_stu_t keys_data;
	uint8_t keysNum = Users_MatchKeysLibrary(USERS_TYPE_CARD, pdata, CARD_LEN_MAX, 0, &keys_data);
	if (keysNum >= KEYS_QTY_CARD)
	{
		return 0XFF; //非法卡片
	}
	else
	{
		return keysNum;
	}
}

static uint8_t Users_PwdIsExist(uint8_t* pdata, uint8_t len)
{
	if (pdata == NULL)
	{
		return 0XFF; //非法卡片
	}
	/* 输入的卡片ID与卡片库比对 */
	NvPassword_stu_t keys_data;
	uint8_t keysNum = Users_MatchKeysLibrary(USERS_TYPE_PWD, pdata, len, 0, &keys_data); //比对密码库;
	
	if (keysNum >= KEYS_QTY_PWD)
	{
		return 0XFF; //非法卡片
	}
	else
	{
		return keysNum;
	}
}

/**
  * @brief  获取是否修改管理密码
  * @note
  *
  * @param	1：是  0:不是
  * 
  * @return 返回结果
  */
static uint8_t User_GetIsModifyAdminPwd(void)
{
	if(g_isModifyAdmin ==1)
	{
		g_isModifyAdmin =0;
		return 1;
	}
	return g_isModifyAdmin;
}

/**
 * @brief 获取总共有多少种密钥类型 返回那种密钥类型存在，这里面的123567 分别对应蓝牙协议里的密钥类型
 * 
 * @return 密钥类型数量
 */
static uint8_t User_GetKeyTypeQty(uint8_t*pData)
{
	uint8_t qty =0;
	if(gUsersParam.qty.pwd != 0) 
	{
		pData[qty] =1;
		qty++;
	}
	if(gUsersParam.qty.fpt != 0)
	{
		pData[qty] =2;
		qty++;
	} 
	if(gUsersParam.qty.card != 0) 
	{
		pData[qty] =3;
		qty++;
	}
	if(gUsersParam.qty.face != 0) 
	{
		pData[qty] =5;
		qty++;
	}	 
	#if defined(FINGERVEIN_SUPPORT)
	if(gUsersParam.qty.fvn != 0)
	{
		pData[qty] =6;
		qty++;
	} 
	#endif
	#if defined(PVN_SUPPORT)
	if(gUsersParam.qty.pvn != 0) 
	{
		pData[qty] =7;
		qty++;
	}
	#endif
	#if defined(EVIDENCE_SUPPORT)
	if(gUsersParam.qty.evidence != 0) 
	{
		pData[qty] =8;
		qty++;
	}
	#endif
	return qty;
}



/**
  * @brief  Users任务函数
  *
  * @note   1.任务函数内不能写阻塞代码
  *         2.任务函数每次运行只处理一个事件
  *         
  * @param  event：当前任务的所有事件
  *
  * @return 返回未处理的事件
  */
static uint32_t Users_Task(uint32_t event)
{
	static FlagStatus  userInitFlag = RESET;
	/* 系统启动事件 */
	if (event & EVENT_SYS_START)
	{
        USERS_LOG("Users Task start\r\n");
		Device_Enable(vFLASH_0);
        /* 注册对外开放的API接口 */
        SYS_API(Users_Verify);
        SYS_API(Users_Add);
        SYS_API(Users_Del);
        SYS_API(Users_DelOnce);
		SYS_API(Users_MatchKeysLibrary);
        SYS_API(Users_GetValidId);
        SYS_API(Users_GetQty);
        SYS_API(Users_GetList);
        SYS_API(Users_CheckAdmin);
		SYS_API(Users_GetAttrPloy);
		SYS_API(Users_SetAttrPloy);
		SYS_API(Users_SetSafeMode);
        SYS_API(Users_GetSafeMode);
		SYS_API(Users_SetActiveCode);
		SYS_API(Users_GetActiveCode);
		SYS_API(Users_SetActiveCodeStatus);
		SYS_API(Users_SetAteFlag);
		SYS_API(Users_SetKeysQty);
		SYS_API(Users_GetKeysQty);
		SYS_API(Users_SetUrgent);
		SYS_API(Users_OfflinePwd_CreateFactor);
		SYS_API(Users_OfflinePwd_SaveRandom);
        SYS_API(Users_AdminPwdIsEasy);
        SYS_API(Users_IsLockActived);
        SYS_API(Users_GetUrgent);
		SYS_API(Users_OfflinePwdVerifySha256);
		SYS_API(Users_KeyNumIsExist);
		SYS_API(Users_CardIsExist);
		SYS_API(User_GetIsModifyAdminPwd);
		SYS_API(Users_GetKeysLen);
		SYS_API(Users_ModifyPassword);
		SYS_API(Users_ReadKeysNumStatus);
		SYS_API(Users_ReadKeys);
		SYS_API(Users_ReadAdminPassword);
		SYS_API(User_GetKeyTypeQty);
		SYS_API(Users_updata_keys_status);
		SYS_API(Users_PwdIsExist);
		
		if(userInitFlag == RESET)
		{
			userInitFlag = SET;
			Users_Init();//用户参数初始化 
		}
		return ( event ^ EVENT_SYS_START );
    }

    /* 系统休眠事件 */
	if (event & EVENT_SYS_SLEEP)
	{
		Device_Disable(vFLASH_0);
        return ( event ^ EVENT_SYS_SLEEP );
    }
    return 0;
}
COMPONENT_TASK_EXPORT(COMP_USERS, Users_Task, USARS_NV_SIZE);

